Documentation Index
Fetch the complete documentation index at: https://tech.ramses.xyz/llms.txt
Use this file to discover all available pages before exploring further.
Introduction
This guide will cover how to initialize a Pool with full tick data to allow offchain calculations. It is based on the Fetching Pool data example, found in the Uniswap code examples repository. To run this example, check out the guide’s README and follow the setup instructions.If you need a briefer on the SDK and to learn more about how these guides connect to the examples repository, please visit our background page!
Pool object that we can use in the following guides.
This guide will cover:
- Computing the Pool’s address
- Referencing the Pool contract and fetching metadata
- Fetching the positions of all initialized Ticks with multicall
- Fetching all ticks by their indices with a multicall
- Constructing the Pool object
Pool Object that accurately represents the state of a V3 pool at the time we fetched it.
For this guide, the following packages are used:
We will also use the ethers-multicall npm package:
The core code of this guide can be found in fetcher.ts
Configuration
The example accompanying this guide can be configured in theconfig.ts file.
The default configuration defines the rpc endpoint and the pool that is used for this guide:
USDC_TOKEN and WETH_TOKEN are defined in the constants.ts file:
Computing the Pool’s deployment address
In this example, we will construct the USDC - WETH Pool with MEDIUM fees. The SDK provides a method to compute the address:Creating a Pool Contract instance and fetching metadata
Now that we have the address of a USDC - ETH Pool, we can construct an instance of an ethersContract to interact with it.
To construct the Contract we need to provide the address of the contract, its ABI and a provider connected to an RPC endpoint. We get access to the contract’s ABI through the @uniswap/v3-core package (Ramses V3 uses compatible interfaces):
getProvider() function returns an ethers.providers.JsonRpcProvider with either the local or mainnet rpc url that we defined, depending on the Environment that we set in config.ts.
Once we have set up our reference to the contract, we can proceed to access its methods. To construct our offchain representation of the Pool Contract, we need to fetch its liquidity, sqrtPrice, currently active tick and the full Tick data.
We get the liquidity, sqrtPrice and tick directly from the blockchain by calling liquidity()and slot0() on the Pool contract:
sqrtPriceX96 and the currently active tick.
Fetching all Ticks
V3 pools use ticks to concentrate liquidity in price ranges and allow for better pricing of trades. Even though most Pools only have a couple of initialized ticks, it is possible that a pools liquidity is defined by thousands of initialized ticks. In that case, it can be very expensive or slow to get all of them with normal RPC calls. If you are not familiar with the concept of ticks, check out theintroduction.
To access tick data, we will use the ticks function of the V3 Pool contract:
tick parameter that we provide the function with is the index (memory position) of the Tick we are trying to fetch.
To get the indices of all initialized Ticks of the Pool, we can calculate them from the tickBitmaps.
To fetch a tickBitmap function of the V3 Pool:
int16 wordPosition the function accepts is the position of the bitMap we want to fetch.
We can calculate all the position of bitMaps (or words as they are sometimes called) from the tickSpacing of the Pool, which is in turn dependant on the Fee tier.
So to summarise we need 4 steps to fetch all initialized ticks:
- Calculate all bitMap positions from the tickSpacing of the Pool.
- Fetch all bitMaps using their positions.
- Calculate the memory positions of all Ticks from the bitMaps.
- Fetch all Ticks by their memory position.
Multicall
Multicall contracts aggregate results from multiple contract calls and therefore allow sending multiple contract calls in one RPC request. This can improve the speed of fetching large amounts of data significantly and ensures that the data fetched is all from the same block. We will use the Multicall2 contract by MakerDAO. We use theethers-muticall npm package to easily interact with the Contract.
Calculating all bitMap positions
As mentioned, Ramses V3 Pools store bitmaps, also called words, that represent the state of 256 initializable ticks at a time. The value at a bit of a word is 1 if the tick at this index is initialized and 0 if it isn’t. We can calculate the positions of initialized ticks from the words of the Pool. All ticks of Ramses V3 pools are between the indices-887272 and 887272.
We can calculate the minimum and maximum word from these indices and the Pool’s tickSpacing:
Fetching bitMaps from their position
Knowing the positions of words in the Pool contract, we can now fetch them from the Pool using multicall and thetickBitmap read call.
First we initialize our multicall providers and Pool Contract:
multicallProvider creates the multicall request and sends it via the ethers Provider.
Next we loop through all possible word positions and add a tickBitmap call for each:
multicallProvider.all() function to send a multicall and map the results:
Calculating the memory positions of all Ticks
Now that we fetched all bitMaps, we check which ticks are initialized and calculate the tick position from the word index and the tickSpacing of the pool. We check if a tick is initialized inside the word by shifting a bit by the index we are looking at and performing a bitwise AND operation:Fetching all Ticks by their indices
We use the multicallProvider again to execute an aggregated read call for all tick indices. We create an array of call Promises again and use.all() to make our multicall:
Tick objects:
Constructing the Pool
We have everything to construct ourPool now:
