Uniswap Trading Data With Chainlink Functions and The Graph
The full code for this tutorial can be found on .
In the rapidly changing world of cryptocurrency trading, staying ahead of the curve is crucial. Traders need access to accurate, real-time data as market conditions can shift rapidly. This is where Chainlink Functions and The Graph come in handy.
This tutorial will teach you how to utilize the potential of The Graph’s subgraphs, Uniswap router, and Chainlink Functions to implement a dynamic trading strategy.
Understanding Liquidity and Its Significance
The trading ecosystem thrives on liquidity, representing the ease of buying or selling assets without causing significant price fluctuations. Assets with high liquidity are easier to trade and tend to be less volatile in price, making them an attractive pick for traders seeking stability and reliability in their portfolios.
This tutorial focuses on the idea that stronger liquidity implies relatively safer assets. By utilizing liquidity data from Uniswap pools, we can extract valuable insights into the risk associated with asset swaps. With this knowledge at our disposal, we can make more informed trading decisions and better manage our risks.
The Role of Chainlink Functions
Chainlink Functions are essential to our trading strategy as they allow us to access and analyze Uniswap V3 WETH-USD
pool data through a subgraph, an open API that organizes and serves blockchain data. Specifically, we utilize them to retrieve three-day trading volume data, a crucial metric for assessing liquidity.
If our analysis indicates an increase in liquidity for the WETH-USD
pair, we will trigger a Chainlink Function within FunctionsConsumer.sol
. This function will enable us to swap Wrapped Matic in our contract balance to Wrapped Ether, taking advantage of the improving liquidity conditions.
Tailoring the Strategy to Your Needs
We focus on the WETH-USD
pair in the Polygon Mumbai testnet for testing purposes. However, this strategy’s beauty lies in its flexibility. In a production environment, you can choose any token pair that aligns with your trading needs and strategy. The principles and tools discussed here can be applied to various cryptocurrency assets.
Whether you’re a seasoned trader looking to refine your approach or a newcomer seeking a reliable method for cryptocurrency trading, this tutorial is your gateway to leveraging Chainlink Functions and Uniswap data via The Graph for informed decisions. Let’s dive in and unlock the potential of data-driven trading.
Step 1: Setting Up Your Environment
Before we dive into the intricacies of connecting The Graph and Uniswap router using Chainlink Functions, let’s ensure your environment is ready. Here’s a quick rundown of the initial setup:
- Ensure you have the following requirements installed on your computer:
- Clone the Repository: Begin by cloning to your local machine. This will give you access to all the necessary code and files to implement the trading strategy.
- Install Dependencies: Once you’ve cloned the repository, open the directory in your command line and run
npm install
to install all the required dependencies. - Github Personal Access Token: To interact with Gists on GitHub, you’ll need a personal access token. Go to and create a new token. Name it and enable read & write access for Gists. Make sure not to allow any additional permissions. Record the generated token; you’ll need it in just a moment.
- The Graph Network API Key: Your trading strategy relies on data indexed by subgraphs, so you’ll need Network. Be sure to claim queries and check that
FREE REMAINING: 1000
is displayed in your key’sQUERIES TOTAL
column. - Setting Environment Variables: To keep your sensitive information secure, set up encrypted environment variables with
env-enc
. Start by setting an encryption password by runningnpx env-enc set-pw
. Then, use thenpx env-enc
set command to set the required environment variables:
Step 2: Understanding the Key Files
When implementing this trading strategy, two essential files are central:
contracts/FunctionsConsumer.sol
: This smart contract receives data and executes the swap based on your trading strategy.graph_request.js
: This JavaScript code is executed by each node of the Decentralized Oracle Network (DON) to facilitate data requests and fulfillments.
Let’s start by taking a look at graph_request.js
. This JavaScript code is executed by each node of the Decentralized Oracle Network (DON) to facilitate data requests and fulfillments. Let’s break down its functionality step by step.
Setting Up The Request
This code snippet is where the action begins. Let’s break it down:
graphKey
: We start by retrieving the key for The Graph Network, which is essential for authentication and authorization. This key is stored viaenv-enc
and retrieved via the secrets object.graphRequest
: Next, we create anHTTP POST
request usingFunctions.makeHttpRequest
. This request is directed to The Graph API.url
: The URL for the request is dynamically constructed, incorporating thegraphKey
into the URL. This URL points to the specific subgraph that contains the data we need.method
: We specify that this is a POST request.headers
: We set the“Content-Type”
to“application/json”
to indicate that we are sendingJSON
data.- data: Inside the
data
field, we define a GraphQL query. This query fetches data from thepoolDayDatas
of a particular pool identified by its address.
Handling the Response
Once we’ve sent the request, we await the response and store it in graphResponse
. Here’s what happens next:
- We initialize an empty array called
liquidities
to store liquidity data. - We check for no error in the response (
!graphResponse.error
). If there’s no error, we extract liquidity data from the response. - In a loop, we iterate over the first 3 entries in the response data and push the
liquidity
values into theliquidities
array. - If there is an error in the response, we log an error message to the console.
Liquidity Analysis and Return Value
Finally, we perform liquidity analysis based on the data we’ve collected:
- We check whether the liquidity of the most recent entry (
liquidities[0]
) is greater than the liquidity of the previous two entries. If it is, Then the liquidity is NOT increasing, and wereturn Functions.endcodedUint256(0)
- Otherwise, we return
Functions.encodeUint256(1)
- This return value triggers the function to swap
WMATIC
toWETH
.Next, let’s take a look at
contracts/FunctionsConsumer.sol
Contract Structure and Imports
The contract starts with version pragma and imports several libraries and contracts essential for its functionality:
TransferHelper.sol
andISwapRouter.sol
from the Uniswap V3 Periphery provide utility functions for token transfers and access to the Uniswap router.FunctionsClient
andConfirmedOwner
contracts are imported from the Chainlink contracts. FunctionsClient provides interaction functionality with Chainlink Functions, and ConfirmedOwner restricts certain functions to the contract owner.FunctionsRequest.sol
contains utilities for creating and managing Chainlink Functions requests.
Variable Initialization
Let’s break down what each of these variables represents:
donId
: This is the DON ID
(Decentralized Oracle Network ID) to which the Chainlink Functions requests are sent.
s_lastRequestId
: Used to store the last Chainlink Functions request ID generated by the contract. Request IDs are unique identifiers for Chainlink Functions requests and are used to track and retrieve the responses for specific requests.
s_lastResponse
stores the last response received from a Chainlink Functions request.
s_lastError
: Used to store the last error message received from a Chainlink Functions request. If there are issues with a request, such as a failure to fetch data or execute a function, error messages can provide diagnostic information.
swapRouter
: Represents the Uniswap router contract address. The contract uses this router to execute token swaps on the Uniswap decentralized exchange.
WETH
and WMATIC
: Store the addresses of Wrapped Ether (WETH
) and Wrapped Matic (WMATIC
) tokens, respectively. These addresses are constants used within the contract to specify the tokens involved in token swaps.
poolFee
: Represents the pool fee associated with Uniswap V3 liquidity pools. It is set to a constant value of 3000, corresponding to a 0.3% fee on trades in these pools.
Contract Initialization
The contract is initialized in the constructor with a Functions router address and a DON (Decentralized Oracle Network) ID.
This function allows the contract owner to update the DON ID
. The DON ID
refers to the specific Chainlink DON to which requests are sent, and it can be modified as needed.
Sending Chainlink Functions Requests
The sendRequest
function is used to trigger on-demand Chainlink Functions requests. It accepts several parameters:
source
: The JavaScript source code defining the function to be executed.secretsLocation
: The location of secrets (either remote or DON-hosted).encryptedSecretsReference
: A reference to encrypted secrets.args
andbytesArgs
: String and bytes arguments passed into the source code.subscriptionId
: The subscription ID used to pay for the request.callbackGasLimit
: The maximum gas limit for calling thefulfillRequest
function.
Fulfilling Chainlink Functions Requests
The fulfillRequest
function handles the response from the Chainlink Functions request. This implementation stores the response and error and then checks if the response indicates a liquidity drop. If a liquidity drop is detected, it triggers a Uniswap swap using the swapExactInputSingle
function.
Swapping Tokens on Uniswap
The swapExactInputSingle
function executes a token swap on Uniswap using the specified parameters. It first checks the contract’s WMATIC
balance, ensuring sufficient tokens for the swap. Then, it sets the parameters for the swap, including the token input, token output, fee, and other details. Finally, it calls the Uniswap router’s exactInputSingle
function to perform the swap.
Checking Token Balance
The checkBalance
function is a helper function used to check the WMATIC balance of the contract. It ensures that there are enough tokens available for the swap.
Step 3: Testing Locally
Before deploying your strategy to a live blockchain network, it’s wise to test it locally. You can simulate an end-to-end request and fulfillment by running:
Step 4: Deploying to the Blockchain
Once satisfied with your local tests, it’s time to take your strategy live. Deploy and verify the client contract on an actual blockchain network by running:
- *Note that you should have
POLYGONSCAN_API_KEY
set if you use-verify true
, depending on your network.
Step 5: Setting Up Billing
You must create, fund, and authorize a new Functions billing subscription to use Chainlink Functions. Run the following command to achieve this:
Here are a few things to keep in mind:
- Make sure to sign the term of use in the Chainlink Functions app if this is the first time you are using. Please head to the , create a new subscription, and sign the terms of use. See the for more information.
- Ensure your wallet has at least 5 LINK tokens in your balance before running this command. You can obtain testnet LINK tokens at .
- Confirm that you’re using the Polygon Mumbai testnet, and if you plan to use the contract on other networks, adjust the network conditions accordingly. You’ll need to modify the
FunctionsConsumer.sol
file to have a different value for the line if (block.chainid != 80001
).
Step 6: Preparing for the Swap
Before initiating the swap, transfer at least 0.1 WMATIC to the FunctionsConsumer contract. Ensure you have WMATIC in your Metamask wallet. The address for WMATIC
on Polygon Mumbai is 0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889
.
MATIC tokens for the Mumbai testnet can be obtained at the , and MATIC can be swapped to Wrapped Matic (WMATIC
) at .
Step 7: Making an On-Chain Request
The moment of truth has arrived. Make an on-chain request to kickstart your trading strategy:
Ensure you include the parameter --gaslimit
and set it to 300,000.
With these steps completed, you are well on your way to implementing a data-driven trading strategy that leverages Chainlink Functions and Uniswap data.
In this tutorial, we have discovered how Chainlink Functions and The Graph can help traders create a dynamic and data-driven strategy. By understanding the importance of liquidity and analyzing Uniswap pool data, we can make informed decisions and manage risks more effectively. Chainlink Functions have played a crucial role in this process by allowing us to take actions based on liquidity changes. Whether you’re an experienced trader or new to the game, this tutorial provides you with the necessary tools to utilize data for smarter trading. Take advantage of the flexibility of this strategy, personalize it to fit your needs, and explore the world of cryptocurrency trading powered by data.