Inherited by the Factory contract. Main purpose is to hold the Kyber Elastic v2 Pool creation code in a separate address, since its creation code is close to the bytecode size limit of 24kB.
Taken from Balancer Labs's solidity utils repo. The only modification made is the unchecked keyword for sol 0.8 compatibility.
getCreationCodeContracts()
Returns the 2 addresses where the creation code of the contract created by this factory is stored.
getCreationCode()
Returns the creation code of the contract this factory creates.
Taken from Balancer Labs's solidity utils repo. Imported and used by the BaseSplitCodeFactory
contract to handle deployment.
Taken from https://xn–2-umb.com/21/muldiv. Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision. Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits.
mulDivFloor()
Returns (a * b / denominator)
rounded down.
Input | Type | Explanation |
---|---|---|
a |
uint256 |
multiplicand |
b |
uint256 |
multiplier |
denominator |
uint256 |
divisor |
mulDivCeiling()
Similar to mulDivFloor
, but rounded up.
A doubly linked list to be used for tick management.
Field | Type | Explanation |
---|---|---|
previous |
int24 |
previous tick |
next |
int24 |
next tick |
init()
Initializes the LinkedList with the lowestValue and highestValue, where
lowestValue.previous = lowestValue
lowestValue.next
= highestValue
highestValue.previous = lowestValue
highestValue.next = highestValue
Field | Type | Explanation |
---|---|---|
self |
mapping(int24 => Data) |
A mapping of int24 values to the Data struct |
lowestValue |
int24 |
lowest value |
highestValue |
int24 |
highest value |
insert()
Inserts a new value into the LinkedList, given an existing lower value. The new value to be inserted should not be an existing value. Also, the condition lowerValue < newValue < lowerValue.next
should be satisfied.
Field | Type | Explanation |
---|---|---|
self |
mapping(int24 => Data) |
A mapping of int24 values to the Data struct |
newValue |
int24 |
value to be inserted |
lowerValue |
int24 |
highest existing value in the linked list that is < newValue |
remove()
Removes an existing value from the LinkedList. Returns the next lowest value (existingValue.previous
).
Note that no removal is performed if removedValue
happens to be the lowestValue
or highestValue
passed in init()
.
Field | Type | Explanation |
---|---|---|
self |
mapping(int24 => Data) |
A mapping of int24 values to the Data struct |
removedValue |
int24 |
value to be removed |
Contains a function to assist with the addition of signed liquidityDelta to unsigned liquidity.
applyLiquidityDelta()
Adds or remove uint128
liquidityDelta to uint128
liquidity
Field | Type | Explanation |
---|---|---|
liquidity |
uint128 |
Liquidity to be adjusted |
liquidityDelta |
int128 |
quantity change to be applied |
isAddLiquidity |
bool |
true = add liquidity, false = remove liquidity |
Contains constants commonly used by multiple files.
Contains functions for calculating token0 and token1 quantites from differences in prices or from burning reinvestment tokens
getQtysForInitialLockup()
Calculate the token0 and token1 quantities needed for unlocking the pool given an initial price and liquidity.
Input Field | Type | Explanation |
---|---|---|
initialSqrtP |
uint160 |
initial sqrt price raised by 2**96 |
liquidity |
uint128 |
initial liquidity. should be MIN_LIQUIDITY = 100000 |
Return Field | Type | Explanation |
---|---|---|
qty0 |
uint256 |
token0 quantity required |
qty1 |
uint256 |
token1 quantity required |
calcRequiredQty0()
Calculates the token0 quantity between 2 sqrt prices for a given liquidity quantity.
Note that the function assumes that upperSqrtP > lowerSqrtP
.
Field | Type | Explanation |
---|---|---|
lowerSqrtP |
uint160 |
the lower sqrt price |
upperSqrtP |
uint128 |
the upper sqrt price |
liquidity |
int128 |
liquidity quantity |
isAddLiquidity |
bool |
true = add liquidity, false = remove liquidity |
Type | Explanation |
---|---|
int256 |
token0 qty required for position with liquidity between the 2 sqrt prices |
Generally, if the return value > 0, it will be transferred into the pool. Conversely, if the return value < 0, it will be transferred out of the pool.
calcRequiredQty1()
Calculates the token1 quantity between 2 sqrt prices for a given liquidity quantity.
Note that the function assumes that upperSqrtP > lowerSqrtP
.
Field | Type | Explanation |
---|---|---|
lowerSqrtP |
uint160 |
the lower sqrt price |
upperSqrtP |
uint128 |
the upper sqrt price |
liquidity |
int128 |
liquidity quantity |
isAddLiquidity |
bool |
true = add liquidity, false = remove liquidity |
Type | Explanation |
---|---|
int256 |
token0 qty required for position with liquidity between the 2 sqrt prices |
Generally, if the return value > 0, it will be transferred into the pool. Conversely, if the return value < 0, it will be transferred out of the pool.
getQty0FromBurnRTokens()
Calculates the token0 quantity to be sent to the user for a given amount of reinvestment tokens to be burnt.
Input Field | Type | Explanation |
---|---|---|
sqrtP |
uint160 |
the current sqrt price |
liquidity |
uint128 |
expected change in reinvestment liquidity due to the burning of reinvestment tokens |
getQty1FromBurnRTokens()
Calculates the token1 quantity to be sent to the user for a given amount of reinvestment tokens to be burnt.
Input Field | Type | Explanation |
---|---|---|
sqrtP |
uint160 |
the current sqrt price |
liquidity |
uint128 |
expected change in reinvestment liquidity due to the burning of reinvestment tokens |
divCeiling()
Returns ceil(x / y)
. y
should not be zero.
getSmallerRootOfQuadEqn()
Given a variant of the quadratic equation \(ax^2 - 2bx + c - 0\) where \(a\), \(b\) and \(c > 0\), calculate the smaller root via the quadratic formula.
Returns \(\frac{b - \sqrt{b^2 - ac}}{a}\)
Input Field | Type |
---|---|
a |
uint256 |
b |
uint256 |
c |
uint256 |
sqrt()
Unchanged from Elastic v1. Calculates the square root of a value using the Babylonian method.
Contains a helper function to calculate reinvestment tokens to be minted given an increase in reinvestment liquidity.
calcRMintQty()
Given the difference between reinvestL
and reinvestLLast
, calculate how many reinvestment tokens are to be minted.
\(rMintQty = rTotalSupply * \frac{reinvestL - reinvestL_{Last}}{reinvestL_{Last}} * \frac{baseL}{baseL + reinvestL}\)
Input Field | Type | Explanation |
---|---|---|
reinvestL |
uint256 |
latest reinvestment liquidity value. Should be >= reinvestLLast |
reinvestLLast |
uint256 |
reinvestmentLiquidityLast value |
baseL |
uint256 |
active base liquidity |
rTotalSupply |
uint256 |
total supply of reinvestment token |
Contains methods for safely casting between different types.
toUint32()
Casts a uint256
to a uint32
. Reverts on overflow.
toInt128()
Casts a uint128
to a int128
. Reverts on overflow.
toUint128()
Casts a uint256
to a uint128
. Reverts on overflow.
revToUint128()
Given int128 y
, returns uint128 z = -y
.
toUint160()
Casts a uint256
to a uint160
. Reverts on overflow.
toInt256()
Casts a uint256
to a int256
. Reverts on overflow.
revToInt256()
Cast a uint256
to a int256
and reverses the sign. Reverts on overflow.
revToUint256()
Given int256 y
, returns uint256 z = -y
.
Contains the logic needed for computing swap input / output amounts and fees. The primary function to look at is computeSwapStep
, as it is where the bulk of the swap flow logic is in, and where calls to the other functions in the library are made.
computeSwapStep()
Computes the actual swap input / output amounts to be deducted or added, the swap fee to be collected and the resulting price.
Field | Type | Explanation |
---|---|---|
liquidity |
uint256 |
active base liquidity + reinvestment liquidity |
currentSqrtP |
uint160 |
current sqrt price |
targetSqrtP |
uint160 |
sqrt price limit nextSqrtP can take |
feeInBps |
uint256 |
swap fee in basis points |
specifiedAmount |
int256 |
amount remaining to be used for the swap |
isExactInput |
bool |
true if specifiedAmount refers to input amount, false if specifiedAmount refers to output amount |
isToken0 |
bool |
true if specifiedAmount is in token0, false if specifiedAmount is in token1 |
Field | Type | Explanation |
---|---|---|
usedAmount |
int256 |
actual amount to be used for the swap. >= 0 if isExactInput = true, <= 0 if isExactInput = false |
returnedAmount |
int256 |
output qty (<= 0) to be accumulated if isExactInput = true, input qty (>= 0) if isExactInput = false |
deltaL |
uint256 |
collected swap fee, to be incremented to reinvest liquidity |
nextSqrtP |
uint160 |
new sqrt price after the computed swap step |
nextSqrtP
should not exceed targetSqrtP
.
calcReachAmount()
Calculates the amount needed to reach targetSqrtP
from currentSqrtP
. Note that currentSqrtP
and targetSqrtP
are casted from uint160 to uint256 as they are multiplied by TWO_BPS (20_000)
or feeInBps
.
The mathematical formulas are provided below for reference.
isExactInput | isToken0 | Formula |
---|---|---|
true |
true |
\(\frac{2*BPS*L(\sqrt{p_c} - \sqrt{p_n})}{\sqrt{p_c}(2*BPS*\sqrt{p_n} - fee\sqrt{p_c})}\) (>0) |
true |
false |
\(\frac{2*BPS*\sqrt{p_c}*L(\sqrt{p_n} - \sqrt{p_c})}{(2*BPS*\sqrt{p_c} - fee\sqrt{p_n})}\) (>0) |
false |
true |
\(-\frac{2*BPS*L(\sqrt{p_n} - \sqrt{p_c})}{\sqrt{p_c}(2*BPS*\sqrt{p_n} - fee\sqrt{p_c})}\) (<0) |
false |
false |
\(-\frac{2*BPS*\sqrt{p_c}*L(\sqrt{p_c} - \sqrt{p_n})}{(2*BPS*\sqrt{p_c} - fee\sqrt{p_n})}\) (<0) |
Note that while cases 1 and 3 and cases 2 and 4 are mathematically equivalent, the implementation differs by performing a double negation for the exact output cases. It takes the difference of \(\sqrt{p_n}\) and \(\sqrt{p_c}\) in the numerator (>0), then performing a second negation.
Input Field | Type | Formula Variable | Explanation |
---|---|---|---|
liquidity |
uint256 |
\(L\) | active base liquidity + reinvestment liquidity |
currentSqrtP |
uint160 |
\(\sqrt{p_c}\) | current sqrt price |
targetSqrtP |
uint160 |
\(\sqrt{p_n}\) | sqrt price limit nextSqrtP can take |
feeInBps |
uint256 |
\(fee\) | swap fee in basis points |
isExactInput |
bool |
N.A. | true / false if specified swap amount refers to input / output amount respectively |
isToken0 |
bool |
N.A. | true / false if specified swap amount is in token0 / token1 respectively |
estimateIncrementalLiquidity()
Estimates deltaL
, the swap fee to be collected based on amountSpecified. This is called only for the final swap step, where the next (temporary) tick will not be crossed.
In the case where exact input is specified, the formula is rather straightforward.
isToken0 | Formula |
---|---|
true |
\(\frac{delta*fee*\sqrt{p_c}}{2*BPS}\) |
false |
\(\frac{delta*fee}{2*BPS*\sqrt{p_c}}\) |
In the case where exact ouput is specified, a quadratic equation has to be solved. The desired result is the smaller root of the quadratic equation.
isToken0 | Formula |
---|---|
true |
\(fee*(\Delta{L})^2-2[(BPS-fee)*L-BPS*delta*\sqrt{p_c}]\Delta{L}+fee*L*delta*\sqrt{p_c}=0\) |
false |
\(fee*(\Delta{L})^2-2[(BPS-fee)*L-\frac{BPS*delta}{\sqrt{p_c}}]\Delta{L}+\frac{fee*L*delta}{\sqrt{p_c}}=0\) |
Input Field | Type | Formula Variable | Explanation |
---|---|---|---|
absDelta |
uint256 |
\(delta\) | \({|}\)usedAmount \({|}\), absolute value of usedAmount (actual amount used for swap) |
liquidity |
uint256 |
\(L\) | active base liquidity + reinvestment liquidity |
currentSqrtP |
uint160 |
\(\sqrt{p_c}\) | current sqrt price |
feeInBps |
uint256 |
\(fee\) | swap fee in basis points |
isExactInput |
bool |
N.A. | true / false if specified swap amount refers to input / output amount respectively |
isToken0 |
bool |
N.A. | true / false if specified swap amount is in token0 / token1 respectively |
calcIncrementalLiquidity()
Calculates deltaL
, the swap fee to be collected based on amountSpecified. This is called for an intermediate swap step, where the next (temporary) tick will be crossed.
The mathematical formulas are provided below for reference.
isExactInput | isToken0 | Formula |
---|---|---|
true |
true |
\(\sqrt{p_n}*(\frac{L}{\sqrt{p_c}}+|delta|)-L\) |
true |
false |
\(\frac{(L*\sqrt{p_c})+|delta|}{\sqrt{p_n}}-L\) |
false |
true |
\(\sqrt{p_n}*(\frac{L}{\sqrt{p_c}}-|delta|)-L\) |
false |
false |
\(\frac{(L*\sqrt{p_c})-|delta|}{\sqrt{p_n}}-L\) |
Input Field | Type | Formula Variable | Explanation |
---|---|---|---|
absDelta |
uint256 |
|\(delta\)| | \({|}\)usedAmount \({|}\), absolute value of usedAmount (actual amount used for swap) |
liquidity |
uint256 |
\(L\) | active base liquidity + reinvestment liquidity |
currentSqrtP |
uint160 |
\(\sqrt{p_c}\) | current sqrt price |
nextSqrtP |
uint160 |
\(\sqrt{p_n}\) | next sqrt price |
isExactInput |
bool |
N.A. | true / false if specified swap amount refers to input / output amount respectively |
isToken0 |
bool |
N.A. | true / false if specified swap amount is in token0 / token1 respectively |
calcFinalPrice()
Calculates the sqrt price of the final swap step where the next (temporary) tick will not be crossed.
The mathematical formulas are provided below for reference.
isExactInput | isToken0 | Formula |
---|---|---|
true |
true |
\(\frac{(L+\Delta{L})\sqrt{p_c}}{L+|delta|\sqrt{p_c}}\) |
true |
false |
\(\frac{L\sqrt{p_c}+|delta|}{L+\Delta{L}}\) |
false |
true |
\(\frac{(L+\Delta{L})\sqrt{p_c}}{L-|delta|\sqrt{p_c}}\) |
false |
false |
\(\frac{L\sqrt{p_c}-|delta|}{L+\Delta{L}}\) |
Input Field | Type | Formula Variable | Explanation |
---|---|---|---|
absDelta |
uint256 |
|\(delta\)| | \({|}\)usedAmount \({|}\), absolute value of usedAmount (actual amount used for swap) |
liquidity |
uint256 |
\(L\) | active base liquidity + reinvestment liquidity |
deltaL |
uint256 |
\(\Delta{L}\) | collected swap fee |
currentSqrtP |
uint160 |
\(\sqrt{p_c}\) | current sqrt price |
isExactInput |
bool |
N.A. | true / false if specified swap amount refers to input / output amount respectively |
isToken0 |
bool |
N.A. | true / false if specified swap amount is in token0 / token1 respectively |
calcReturnedAmount()
Calculates returnedAmount
for the computeSwapStep
function. Rounds down when isExactInput = true
(calculating output < 0) so that we avoid sending too much. Conversely, rounds up when isExactInput = false
to ensure sufficient input > 0 will be received.
The mathematical formulas are provided below for reference.
isToken0 = true
The formula is actually the same, with the difference being made to the operands to ensure the price difference is non-negative.
isExactInput | Formula |
---|---|
true |
\(\Delta{L}\sqrt{p_n}-L(\sqrt{p_c}-\sqrt{p_n})\) |
false |
\(\Delta{L}\sqrt{p_n}+L(\sqrt{p_n}-\sqrt{p_c})\) |
isToken0 = false
\(\frac{L+\Delta{L}}{\sqrt{p_n}} - \frac{L}{\sqrt{p_c}}\)
Input Field | Type | Formula Variable | Explanation |
---|---|---|---|
liquidity |
uint256 |
\(L\) | active base liquidity + reinvestment liquidity |
currentSqrtP |
uint160 |
\(\sqrt{p_c}\) | current sqrt price |
nextSqrtP |
uint160 |
\(\sqrt{p_n}\) | next sqrt price |
deltaL |
uint256 |
\(\Delta{L}\) | collected swap fee |
isExactInput |
bool |
N.A. | true / false if specified swap amount refers to input / output amount respectively |
isToken0 |
bool |
N.A. | true / false if specified swap amount is in token0 / token1 respectively |
Contains functions for computing square root prices from ticks and vice versa. Adapted from Uniswap V3's TickMath library.
Field | Type | Value | Explanation |
---|---|---|---|
MIN_TICK |
int24 |
-887272 |
Minimum possible tick = \({log_{1.0001}2^{-128}}\) |
MAX_TICK |
int24 |
887272 |
Minimum possible tick = \({log_{1.0001}2^{128}}\) |
MIN_SQRT_RATIO |
uint160 |
4295128739 |
getSqrtRatioAtTick(MIN_TICK) |
MAX_SQRT_RATIO |
uint160 |
1461446703485210103287273052203988822378723970342 |
getSqrtRatioAtTick(MAX_TICK) |
getSqrtRatioAtTick()
Given a int24 tick
, calculates \({\sqrt{1.0001^{tick}} * 2^{96}}\).
getTickAtSqrtRatio()
Given a square root price ratio uint160 sqrtP
, calculates the greatest tick
such that getSqrtRatioAtTick(tick) <= sqrtP
.
Note that MIN_SQRT_RATIO <= sqrtP <= MAX_SQRT_RATIO
, otherwise the function will revert.
getMaxNumberTicks()
Used to calculate the maximum liquidity allowable per tick. This function calculates the maximum number of ticks that can be inserted into the LinkedList, given a tickDistance
.
Field | Type | Explanation |
---|---|---|
_tickDistance |
int24 |
Ticks can only be initialized at multiples of this value. |
Handles deployment of Kyber Elastic v2 pools and where administrative configurations are held, such as the whitelisting of NFT position managers, and government fee settings.
parameters
Used by the Pool's constructor to fetch the parameters. The reason why they are not passed directly is for the automatic contract verification on Etherscan.
Field | Type | Explanation |
---|---|---|
factory |
address |
this contract's address |
poolOracle |
address |
the pool oracle contract's address to store all observations |
token0 |
address |
first pool token by address sort order |
token1 |
address |
second pool token by address sort order |
swapFeeBps |
uint16 |
fee to be collected upon every swap in the pool, in basis points |
_tickDistance |
int24 |
Minimum number of ticks between initialized ticks |
poolInitHash
Type | Explanation |
---|---|
bytes32 |
keccak256 hash of the pool's creation code. This is accessed by periphery contracts for the deterministic computation of a pool's address |
configMaster
Type | Explanation |
---|---|
address |
The address that is able to modify different settings and parameters |
whitelistDisabled
Type | Explanation |
---|---|
bool |
If true, anyone can directly mint liquidity from the pool. Otherwise, only whitelisted addresses are able to do so |
vestingPeriod
Type | Explanation |
---|---|
uint32 |
The maximum time duration for which LP fees are proportionally burnt upon LP removals |
feeAmountTickDistance()
Returns the tick distance for a specified fee. Once added, cannot be updated or removed.
Field | Type | Explanation |
---|---|---|
Input, swapFeeBps |
uint16 |
swap fee, in basis points |
Output | int24 |
configured tick distance |
feeConfiguration()
Field | Type | Explanation |
---|---|---|
_feeTo |
address |
recipient of government fees |
_governmentFeeBps |
uint16 |
current government fee charged in basis points. Taken out of swap fee |
getPool()
Returns the pool address for a given pair of tokens and a swap fee. Note that the token order does not matter.
Field | Type | Explanation |
---|---|---|
tokenA |
address |
contract address of either token0 or token1 |
tokenB |
address |
contract address of the other token |
swapFeeBps |
uint16 |
swap fee, in basis points |
Field | Type | Explanation |
---|---|---|
pool |
address |
The pool address. Returns null address if it does not exist |
createPool()
Creates a pool for the given two tokens and fee. The token order does not matter.
The call reverts under the following conditions:
Field | Type | Explanation |
---|---|---|
tokenA |
address |
contract address of either token0 or token1 |
tokenB |
address |
contract address of the other token |
swapFeeBps |
uint16 |
swap fee, in basis points |
Field | Type | Explanation |
---|---|---|
pool |
address |
created pool address |
isWhitelistedNFTManager()
Checks if an address is a whitelisted NFT manager. Returns true if it is, false if it is not.
Field | Type | Explanation |
---|---|---|
sender |
address |
address to be checked |
getWhitelistedNFTManagers()
Returns an array of addresses of all whitelisted NFT managers.
updateConfigMaster()
To update the address of configMaster
. Can only be changed by configMaster
.
Field | Type | Explanation |
---|---|---|
_configMaster |
address |
new config master address |
enableWhitelist()
Sets whitelistDisabled
to false, meaning, only whitelisted addresses are able to call the Pool's mint method. Can only be called by configMaster
.
disableWhitelist()
Sets whitelistDisabled
to true. Will allow anyone to call the Pool's mint method. Can only be called by configMaster
.
addNFTManager()
Whitelists an NFT manager. Returns true if addition was successful, that is if it was not already present. Can only be called by configMaster
.
Field | Type | Explanation |
---|---|---|
_nftManager |
address |
address to be whitelisted |
removeNFTManager()
Removes a whitelisted NFT manager. Returns true if removal was successful, that is if it was not already present. Can only be called by configMaster
.
Field | Type | Explanation |
---|---|---|
_nftManager |
address |
whitelisted address to be removed |
updateVestingPeriod()
Updates the value of vestingPeriod
. Can only be called by configMaster
.
enableSwapFee()
Enables a fee amount with the given tickDistance. The value cannot be updated or removed after setting. Can only be called by configMaster
.
Field | Type | Explanation |
---|---|---|
swapFeeBps |
uint16 |
swap fee, in basis points |
tickDistance |
int24 |
desired tick distance |
updateFeeConfiguration()
Updates the address receiving government fees and government fee to be charged (taken out of swap fee).
Field | Type | Explanation |
---|---|---|
feeTo |
address |
recipient of government fees |
governmentFeeBps |
uint16 |
government fee charged in basis points |
Primarily contains the implementation of actionable items by users, such as adding or removing liquidity, executing swaps or flash loans, and burning reinvestment tokens in exchange for fees collected.
unlockPool()
Provides initial liquidity and sets initial price for the pool. All other actions cannot be performed prior to the execution of this function.
Note that this function should also be called at most once.
Field | Type | Explanation |
---|---|---|
initialSqrtP |
uint160 |
Initial sqrt price, multiplied by \(2^{96}\) |
data |
bytes |
Data, if any, to be passed into the callback function |
Field | Type | Explanation |
---|---|---|
qty0 |
uint256 |
token0 quantity permanently locked in the pool |
qty1 |
uint256 |
token1 quantity permanently locked in the pool |
mint()
Adds liquidity to a specified recipient/tickLower/tickUpper position. Any token0 or token1 owed for the liquidity provision have to be paid for in the callback function.
Also sends reinvestment tokens (fees) to the recipient for any fees collected by the position. Reinvestment tokens have to be burnt via burnRTokens in exchange for token0 and token1.
Field | Type | Explanation |
---|---|---|
recipient |
address |
address for which the added liquidity is credited to. Equivalent to position owner |
tickLower |
int24 |
position's lower tick |
tickUpper |
int24 |
position's upper tick |
ticksPrevious |
int24[2] |
an array containing 2 values tickLowerPrevious and tickUpperPrevious which are expected to be the nearest initialized tick <= tickLower and tickUpper respectively |
qty |
uint128 |
Liquidity quantity to mint |
data |
bytes |
Data, if any, to be passed into the callback function |
Field | Type | Explanation |
---|---|---|
qty0 |
uint256 |
token0 quantity sent to the pool in exchange for specified liquidity quantity |
qty1 |
uint256 |
token1 quantity sent to the pool in exchange for specified liquidity quantity |
feeGrowthInside |
uint256 |
position's updated feeGrowthInside value |
burn()
Removes liquidity from the caller. In other words, the caller is treated as the position owner.
Also sends reinvestment tokens (fees) to the caller for any fees collected by the position. Reinvestment tokens have to be burnt via burnRTokens in exchange for token0 and token1.
Field | Type | Explanation |
---|---|---|
tickLower |
int24 |
position's lower tick |
tickUpper |
int24 |
position's upper tick |
qty |
uint128 |
Liquidity quantity to burn |
Field | Type | Explanation |
---|---|---|
qty0 |
uint256 |
token0 quantity sent to the caller |
qty1 |
uint256 |
token1 quantity sent to the caller |
feeGrowthInside |
uint256 |
position's updated feeGrowthInside value |
burnRTokens()
Burns reinvestment tokens in exchange to receive the fees collected in token0 and token1.
Field | Type | Explanation |
---|---|---|
qty |
uint256 |
Reinvestment token quantity to burn |
bool |
isLogicalBurn |
false = burning tokens without receiving any fees in exchange. true = fees should be calculated and sent |
The use-case for burning tokens whilst leaving the collected fees in the pool is the anti-snipping attack mechanism.
Field | Type | Explanation |
---|---|---|
qty0 |
uint256 |
token0 quantity sent to the caller |
qty1 |
uint256 |
token1 quantity sent to the caller |
tweakPosZeroLiq()
Update the position data to sync the latest fee growth to Position Manager in order to update the latest data for reinvestment tokens of a position.
Field | Type | Explanation |
---|---|---|
tickLower |
int24 |
The position's lower tick |
tickUpper |
int24 |
The position's upper tick |
Field | Type | Explanation |
---|---|---|
feeGrowthInsideLast |
uint256 |
The position's updated feeGrowthInside value |
swap()
Swap token0 -> token1, or vice versa. Note that swaps will either fully use up the specified swap quantity, or swap up to the specified price limit, depending on whichever condition is satisfied first.
Field | Type | Explanation |
---|---|---|
recipient |
address |
address to receive the swap output |
swapQty |
int256 |
swap quantity, which implicitly configures the swap as exact input (>0), or exact output (<0) |
isToken0 |
bool |
whether the swapQty is specified in token0 (true) or token1 (false) |
limitSqrtP |
uint160 |
sqrt price limit to reach |
data |
bytes |
Data, if any, to be passed into the callback function |
To specify an unlimited price limit for a swap, use the following values.
isToken0 |
swapQty |
Value |
---|---|---|
true |
> 0 | MIN_SQRT_RATIO + 1 |
true |
< 0 | MAX_SQRT_RATIO - 1 |
false |
> 0 | MAX_SQRT_RATIO - 1 |
false |
< 0 | MIN_SQRT_RATIO + 1 |
Field | Type | Explanation |
---|---|---|
qty0 |
int256 |
exact token0 qty sent to recipient if < 0. Minimally received quantity if > 0 |
qty1 |
int256 |
exact token1 qty sent to recipient if < 0. Minimally received quantity if > 0 |
flash()
Request for token0 and/or token1 and pay it back in the same transaction, plus a fee, in the callback. Fees collected are distributed to all rToken holders since no rTokens are minted from it.
Field | Type | Explanation |
---|---|---|
recipient |
address |
address which will receive the token0 and token1 quantities |
qty0 |
uint256 |
token0 quantity to be loaned to the recipient |
qty1 |
uint256 |
token1 quantity to be loaned to the recipient |
data |
bytes |
Data, if any, to be passed into the callback function |
Contains all variables and getter methods to be used by the Pool contract. Inherited by PoolTickState.
factory
Type | Explanation |
---|---|
IFactory |
Canonical factory address fetched upon pool creation |
poolOracle
Type | Explanation |
---|---|
IPoolOracle |
Canonical pool oracle address fetched upon pool creation |
token0
Type | Explanation |
---|---|
IERC20 |
First of the two tokens of the pool, sorted by address |
token1
Type | Explanation |
---|---|
IERC20 |
Second of the two tokens of the pool, sorted by address |
maxTickLiquidity
Type | Explanation |
---|---|
uint128 |
Maximum gross liquidity that an initialized tick can have. This is to prevent overflow the pool's active base liquidity (uint128) |
swapFeeBps
Type | Explanation |
---|---|
uint16 |
fee to be charged for a swap in basis points |
tickDistance
Type | Explanation |
---|---|
int24 |
Ticks can only be initialized and used at multiples of this value |
For instance, a tickDistance of 5 means ticks can be initialized every 5th tick, i.e., …, -10, -5, 0, 5, 10, …
ticks()
Retrieve information about a specified int24
tick.
Output Field | Type | Explanation |
---|---|---|
liquidityGross |
uint128 |
total liquidity amount from positions that uses this tick as a lower or upper tick |
liquidityNet |
int128 |
how much liquidity changes when the pool tick crosses up this tick |
feeGrowthOutside |
uint256 |
fee growth on the other side of the tick relative to the current tick. Appendix-A |
secondsPerLiquidityOutside |
uint128 |
seconds spent on the other side of the tick relative to the current tick. Appendix-A |
initializedTicks()
Returns the previous and next initialized ticks from the specified tick.
If the specified tick is uninitialized, the returned values are zero.
Output Field | Type | Explanation |
---|---|---|
previous |
int24 |
Next initalized tick below the specified tick |
next |
int24 |
Next initalized tick above the specified tick |
getPositions()
Returns the information about a position.
Field | Type | Explanation |
---|---|---|
owner |
address |
position owner |
tickLower |
int24 |
position's lower tick |
tickUpper |
int24 |
position's upper tick |
Field | Type | Explanation |
---|---|---|
liquidity |
uint128 |
position's liquidity amount |
feeGrowthInsideLast |
uint256 |
last cached fee growth inside the position as of the last action performed |
getPoolState()
Primarily returns the pool's current price and ticks, and whether it is locked.
Field | Type | Explanation |
---|---|---|
sqrtP |
uint160 |
current sqrt price, multiplied by \(2^{96}\) |
currentTick |
int24 |
current tick that closely reflects sqrtP |
nearestCurrentTick |
int24 |
nearest initialized tick that is <= currentTick |
locked |
bool |
true if pool is locked, false otherwise |
getLiquidityState()
Fetches the pool's liquidity values.
Field | Type | Explanation |
---|---|---|
baseL |
uint128 |
total liquidity provided by active positions |
reinvestL |
uint128 |
liquidity is reinvested into the pool |
reinvestLLast |
uint128 |
last cached value of reinvestL , used for calculating reinvestment token qty |
getFeeGrowthGlobal()
Returns the all-time fee growth per unit of liquidity of the pool. More information can be found here.
getSecondsPerLiquidityData()
Field | Type | Explanation |
---|---|---|
secondsPerLiquidityGlobal |
uint128 |
all-time seconds per unit of liquidity of the pool. More information can be found here |
lastUpdateTime |
uint32 |
timestamp of last performed updated to secondsPerLiquidityGlobal |
getSecondsPerLiquidityInside()
Calculates and returns the active time per unit of liquidity until up to the current timestamp.
Field | Type | Explanation |
---|---|---|
tickLower |
int24 |
a lower tick |
tickUpper |
int24 |
an upper tick |
Field | Type | Explanation |
---|---|---|
secondsPerLiquidityInside |
uint128 |
active time between tickLower and tickUpper . Note that its value is multiplied by \(2^{96}\). More information can be found here |
_initPoolStorage()
Used by the pool to initialize relevant pool variables.
_positionKey()
Calculates the key to the positions mapping. It is simply the keccak256 hash of a specified address and lower and upper ticks.
Inherits PoolStorage. Contains functions for updating a tick's, position's or pool's state.
_updatePosition()
Calls _updateTick
on a position's lower and upper tick, calculates the fee growth inside between the 2 ticks and updates the position by calling _updatePositionData()
.
Returns the calculated reinvestment tokens to be minted for the position's accumulated fees.
_updateLiquidityAndCrossTick()
Called by the pool when crossing a tick. Updates the tick's outside values (read more here), and applies any change in liquidity to the pool's base liquidity.
Returns the new base liquidity and next tick values.
_updatePoolData()
Called after a pool swap's calculations are completed, and new values are to be assigned to the pool's price, liquidity and tick values.
_getInitialSwapData()
Returns the stored pool's price, liquidity and tick values before swap calculations are to be performed.
_updatePositionData()
Updates a position's liquidity and feeGrowthInside value. Also calculates the reinvestment tokens to be minted for the position's accumulated fees.
_updateTick()
Initializes / updates / deletes a tick's state (liquidity, outside values) and if required, inserts and removes the tick from the linked list by calling _updateTickList()
.
_updateTickList()
Add / remove a specified tick to / from the linked list. No changes are applied if the specified tick is either the MIN_TICK
or MAX_TICK
.
rescueFund()
Rescue fund from contract if someone transfer into pool.
Input Field | Type | Explanation |
---|---|---|
token |
address |
token address |
amount |
uint256 |
amount of token |
initializeOracle()
Initialize oracle pool at time.
Input Field | Type | Explanation |
---|---|---|
time |
uint32 |
timestamp |
write()
Write a new observation to pool. Also update index and cardinality with observation index and observation cardinality.
Input Field | Type | Explanation |
---|---|---|
timestamp |
uint32 |
token address |
tick |
int24 |
tick number |
liquidity |
uint128 |
writeNewEntry()
Write a new observation to pool. Also update index and cardinality.
Input Field | Type | Explanation |
---|---|---|
timestamp |
uint32 |
token address |
tick |
int24 |
tick number |
liquidity |
uint128 |
increaseObservationCardinalityNext()
Anyone can pay storage gas to increase the observation size of their desired Elastic pool.
Input Field | Type | Explanation |
---|---|---|
pool |
address |
pool address |
observationCardinalityNext |
uint16 |
next cardinality number |
observeFromPool()
Read observation from a pool with the latest state of the pool.
Input Field | Type | Explanation |
---|---|---|
pool |
address |
pool address |
secondsAgos |
uint32[] |
list second input ago |
observeSingleFromPool()
Read a single observation from a pool with the latest state of the pool.
Input Field | Type | Explanation |
---|---|---|
pool |
address |
pool address |
secondsAgos |
uint32 |
second input ago |
getPoolObservation()
Get current state of pool observation.
Input Field | Type | Explanation |
---|---|---|
pool |
address |
pool address |
getObservationAt()
Get current state of pool observation at an index.
Input Field | Type | Explanation |
---|---|---|
pool |
address |
pool address |
index |
uint256 |
index data |
Validate if the block timestamp has not reached the deadline yet, use for transactions with a deadline.
onlyNotExpired()
Reverts if the current block's timestamp is greater than the specified deadline
.
Field | Type | Explanation |
---|---|---|
deadline |
uint256 |
Timestamp to check against current block's timestamp |
_blockTimestamp()
Returns the current block timestamp. Used for overriding by mock contracts for tests.
Nonfungible tokens that support an approve via signature, i.e. permit for ERC721.
Immutable variables that are used by Periphery contracts.
Field | Type | Explanation |
---|---|---|
factory |
address |
Factory contract address |
WETH |
address |
Canonical WETH address |
poolInitHash |
bytes32 |
keccak256 hash of the pool's creation code. Used to compute the pool address without reading storage from the Factory |
A helper contract to handle transfers, wrapping and unwrapping of tokens.
unwrapWeth()
Unwraps the contract's entire WETH balance to ETH, then transfers them to the recipient.
Input Field | Type | Explanation |
---|---|---|
minAmount |
uint256 |
Contract's WETH balance should not be lower than this amount |
recioient |
address |
Desired recipient of unwrapped ETH |
transferAllTokens()
Transfers the contract's entire token
balance to the recipient
Input Field | Type | Explanation |
---|---|---|
token |
address |
Token to transfer |
minAmount |
uint256 |
Contract's token balance should not be lower than this amount |
recipient |
address |
Desired recipient of the token |
refundEth()
Transfers all ETH balance to the sender.
_transferTokens()
Internal function to help transfer tokens from the sender
to the recipient
. If token
is WETH and the contract has enough ETH balance, then wrap and transfer WETH, otherwise use TokenHelper to handle transfers.
Input Field | Type | Explanation |
---|---|---|
token |
address |
Token to transfer |
sender |
address |
Address to pull token funds from |
recipient |
address |
Desired recipient of the token |
amount |
uint256 |
Amount to be transferred |
Inherits RouteTokenHelper. Contains additional functions to charge a fee for transfers as well.
unwrapWethWithFee()
Unwraps the contract's entire WETH balance to ETH, then transfers them to the recipient
. Charges a fee which is transferred to feeRecipient
Input Field | Type | Explanation |
---|---|---|
minAmount |
uint256 |
Contract's WETH balance should not be lower than this amount |
recipient |
address |
Desired recipient of unwrapped ETH |
feeBps |
uint256 |
Fee to charge in basis points |
feeRecipient |
address |
Address to receive the fee charged |
transferAllTokensWithFee()
Transfers the contract's entire token
balance to the recipient. Charges a fee which is transferred to feeRecipient
.
Input Field | Type | Explanation |
---|---|---|
token |
address |
Token to transfer |
minAmount |
uint256 |
Contract's token balance should not be lower than this amount |
recipient |
address |
Desired recipient of the token |
feeBps |
uint256 |
Fee to charge in basis points |
feeRecipient |
address |
Address to receive the fee charged |
Enables calling multiple methods in a single call to the contract.
multicall()
Uses delegateCall
to sequentially execute functions, then return the result of each execution.
Field | Type | Explanation |
---|---|---|
data |
bytes[] |
encoded function data for each of the calls to make to this contract |
Field | Type | Explanation |
---|---|---|
results |
bytes[] |
results from each of the calls passed in |
A helper contract to handle liquidity related actions, including mint/add/remove liquidity.
Used when minting a new position or adding liquidity to an existing one.
Field | Type | Explanation |
---|---|---|
token0 |
address |
first token of the pool |
token1 |
address |
second token of the pool |
fee |
uint16 |
the pool's swap fee |
tickLower |
int24 |
position's lower tick |
tickUpper |
int24 |
position's upper tick |
ticksPrevious |
int24[2] |
an array containing 2 values tickLowerPrevious and tickUpperPrevious which are expected to be the nearest initialized tick <= tickLower and tickUpper respectively |
amount0Desired |
uint256 |
token0 amount user wants to add |
amount1Desired |
uint256 |
token1 amount user wants to add |
amount0Desired |
uint256 |
minimum token0 amount that should be used |
amount1Desired |
uint256 |
minimum token1 amount that should be used |
Data for callback from Pool contract.
Field | Type | Explanation |
---|---|---|
token0 |
address |
first token of the pool |
token1 |
address |
second token of the pool |
fee |
uint16 |
the pool's swap fee |
source |
address |
address to transfer token0/token1 from |
mintCallback()
Mint callback function implementation called by a Pool.
Input Field | Type | Explanation |
---|---|---|
deltaQty0 |
uint256 |
token0 amount requested by the pool |
deltaQty1 |
uint256 |
token1 amount requested by the pool |
data |
bytes |
Encoded CallbackData |
_addLiquidity()
Add liquidity to a pool. token0 and token1 should be in the correct order, i.e token0 < token1.
Type | Explanation |
---|---|
AddLiquidityParams |
Parameters for addiing liquidity to a pool |
Field | Type | Explanation |
---|---|---|
liquidity |
uint128 |
amount of liquidity added |
amount0 |
uint256 |
amount of token0 required |
amount1 |
uint256 |
amount of token1 required |
feeGrowthInsideLast |
uint256 |
latest feeGrowthInsideLast calculated by the pool |
pool |
IPool |
pool address |
_callbackData()
Function to encode input parameters to CallbackData
Input Field | Type | Explanation |
---|---|---|
token0 |
address |
first token of the pool |
token1 |
address |
second token of the pool |
fee |
uint16 |
the pool's swap fee |
_getPool()
Function for computing the pool address with the given input parameters.
Input Field | Type | Explanation |
---|---|---|
token0 |
address |
first token of the pool |
token1 |
address |
second token of the pool |
fee |
uint16 |
the pool's swap fee |
The motivation and explanation of the mechanism can be found here. The function containing the bulk of the logic is update()
.
Field | Type | Formula Variable | Explanation |
---|---|---|---|
lastActionTime |
uint32 |
\(t_{last}\) | timestamp of last action performed |
lockTime |
uint32 |
\(t_{lock}\) | average start time of lock schedule |
unlockTime |
uint32 |
\(t_{unlock}\) | average unlock time of locked fees |
feesLocked |
uint32 |
\(fee_{locked}\) | locked rToken qty since last update |
initialize()
Initializes Data values for a new position. The time variables are set to the current timestamp, while feesLocked
is set to zero.
update()
Updates Data values for an existing position. Calculates the amount of claimable reinvestment tokens to be sent to the user and, in the case of liquidity removal, the amount of burnable reinvestment tokens as well.
\(claimBps_{new} = min(BPS, \frac{t_{now}-t_{lock}}{t_{target}})\)
\(claimBps_{current} = min(BPS, \frac{t_{now}-t_{last}}{t_{unlock} - t_{target}})\) if \(t_{unlock} > t_{target}\), \(BPS\) otherwise
\(fee_{harvest}\) and \(fee_{lock}\) updated through calcFeeProportions()
\(t_{unlock} = \frac{(t_{lock} + t_{target}) * (BPS - claimBps_{new}) * fee_{collect} + t_{unlock} * (BPS - claimBps_{current}) * fee_{locked}}{fee_{lock} * BPS}\)
Field | Type | Formula Variable | Explanation |
---|---|---|---|
self |
Data |
N.A. | stored data values for an existing position |
currentLiquidity |
uint128 |
\(L\) | current position liquidity |
liquidityDelta |
uint128 |
\(\Delta{L}\) | quantity change to be applied |
currentTime |
uint32 |
\(t_{now}\) | current block timestamp |
isAddLiquidity |
bool |
N.A. | true = add liquidity, false = remove liquidity |
feesSinceLastAction |
uint256 |
\(fee_{collect}\) | fees accrued since last action |
vestingPeriod |
uint256 |
\(t_{target}\) | maximum time duration for which LP fees are proportionally burnt upon LP removals |
Field | Type | Formula Variable | Explanation |
---|---|---|---|
feesClaimable |
uint256 |
\(fee_{harvest}\) | claimable reinvestment token amount |
feesBurnable |
uint256 |
\(fee_{burn}\) | reinvestment token amount to burn |
calcFeeProportions()
Calculates the proportion of locked fees and claimable fees given the fee amounts and claimable fee basis points.
\(fee_{harvest} = \frac{claimBps_{current}}{BPS} * fee_{locked} + \frac{claimBps_{new}}{BPS} * fee_{collect}\)
\(fee_{lock} = fee_{locked} + fee_{collect} - fee_{harvest}\)
Field | Type | Formula Variable | Explanation |
---|---|---|---|
currentFees |
uint256 |
\(fee_{locked}\) | currently locked fees |
nextFees |
uint256 |
\(fee_{collect}\) | fees since last action |
currentClaimableBps |
uint256 |
\(claimBps_{current}\) | proportion of claimable / unlocked currentFees in basis points |
nextClaimableBps |
uint256 |
\(claimBps_{new}\) | proportion of claimable nextFees in basis points |
Field | Type | Formula Variable | Explanation |
---|---|---|---|
feesLockedNew |
uint256 |
\(fee_{lock}\) | new fee amount to be locked |
feesClaimable |
uint256 |
\(fee_{harvest}\) | claimable fees to be sent to user |
Solidity Bytes Arrays Utils @author Gonçalo Sá goncalo.sa@consensys.net
Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. The library lets you slice and type cast bytes arrays both in memory and storage.
Contract to calculate the expected amount of liquidity given the amounts of tokens.
getLiquidityFromQty0()
Params:
uint160 lowerSqrtP // a lower sqrt price of the position
uint160 upperSqrtP // a upper sqrt price of the position
uint256 qty0 // the amount of token0 to add
Returns:
uint128 liquidity // amount of liquidity to receive
Get liquidity from qty0 of the first token given the price range.
getLiquidityFromQty1()
Params:
uint160 lowerSqrtP // a lower sqrt price of the position
uint160 upperSqrtP // a upper sqrt price of the position
uint256 qty1 // the amount of token1 to add
Returns:
uint128 liquidity // amount of liquidity to receive
Get liquidity from qty1 of the second token given the price range.
getLiquidityFromQties()
Params:
uint160 currentSqrtP // the current price, e.g the pool's current price
uint160 lowerSqrtP // a lower sqrt price of the position
uint160 upperSqrtP // a upper sqrt price of the position
uint256 qty0 // the amount of token0 to add
uint256 qty1 // the amount of token1 to add
Returns:
uint128 liquidity // amount of liquidity to receive
Get liquidity given the price range and amounts of 2 tokens
Functions for manipulating path data for multihop swaps
ADDR_SIZE = 20 // length of the address, i.e 20 bytes
FEE_SIZE = 2 // length of the fee, i.e 2 bytes
TOKEN_AND_POOL_OFFSET = ADDR_SIZE + FEE_SIZE// the offset of a single token address + pool fee
POOL_DATA_OFFSET = TOKEN_AND_POOL_OFFSET + ADDR_SIZE // the offset of 2 token addresses + pool fee
MULTIPLE_POOLS_MIN_LENGTH = POOL_DATA_OFFSET + TOKEN_AND_POOL_OFFSET // min length that contains at least 2 pools
hasMultiplePools()
Params:
bytes path
Returns:
bool
Return true if the path contains 2 or more pools, false otherwise
numPools()
Params:
bytes path
Returns:
uint256
Returns the number of pools in the path.
decodeFirstPool()
Params:
bytes path
Returns:
address tokenA
address tokenB
uint16 fee
Return the first pool's data from the path, including tokenA, tokenB and fee.
getFirstPool()
Params:
bytes path
Returns:
bytes data
Return the segment corresponding to the first pool in the path.
skipToken()
Params:
bytes path
Returns:
bytes newPath
Skip a token + fee from the buffer and returns the remainder.
Provides a function for deriving a pool address from the factory, tokens, and swap fee
ProAMM
computeAddress()
Params:
address factory // Elastic v2 factory contract
address token0 // the first token of the pool
address token1 // the second token of the pool
uint16 swapFee // the fee of the pool
bytes32 poolInitHash // the keccake256 hash of the Pool creation code
Returns:
address pool // the pool address
Deterministically computes the pool address from the given data.
countInitializedTicksCrossed()
Params:
IPool
int24 nearestCurrentTickBefore
int24 nearestCurrentTickAfter
Returns:
uint32 initializedTicksCrossed
Count the number of initialized ticks have been crossed given the previous/current nearest initialized ticks to the current tick.
A helper contract to transfer token/ETH.
transferToken()
Params:
IERC20 token
uint256 amount
address sender
address receiver
Transfer an amount of ERC20 token from the sender to the receiver.
transferEth()
Params:
uint256 amount
address receiver
Transfer an amount of ETH to the receiver.
The Router contract to handle swapping.
Contains data for swap exact input with a single pool.
ExactInputSingleParams
address tokenIn; // source token to swap
address tokenOut; // dest token to receive
uint16 fee; // fee of the pool to swap
address recipient; // the recipient of tokenOut
uint256 deadline; // deadline for the transaction
uint256 amountIn; // the amount of tokenIn to swap
uint256 minAmountOut;// min acceptable amount of tokenOut
uint160 limitSqrtP; // the limit of sqrt price, partial swap if price reaches the limitation
Contains data for swap exact input with one or multiple pools.
ExactInputParams
bytes path; // contains data to identify list of pools to use for the swap
address recipient; // the recipient of token out
uint256 deadline; // deadline for the transaction
uint256 amountIn; // the amount of token in to swap
uint256 minAmountOut; // the min acceptable amount of token out
Contains data for swap to an exact amount out of token out, using only one pool.
ExactOutputSingleParams:
address tokenIn; // source token to swap
address tokenOut; // dest token to receive
uint16 fee; // fee of the pool
address recipient; // the recipient of tokenOut
uint256 deadline; // deadline for the transaction
uint256 amountOut; // the amount of tokenOut to expect
uint256 maxAmountIn;// the max amount of tokenIn that is allowed to use
uint160 limitSqrtP; // the limit of sqrt price, partial swap if price reaches the limitation
Contains data for swap to an exact amount out of token out using one or multiple pools.
ExactOutputParams
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 maxAmountIn;
swapCallback()
Params:
int256 deltaQty0
int256 deltaQty1
bytes data
Callback function that is be triggerred by the pool when swapping tokens.
Either deltaQty0 or deltaQty1 must be positive. Positive value means the pool (also the caller) is expecting to receive that amount of token.
swapExactInputSingle()
Params:
ExactInputSingleParams params
Returns:
uint256 amountOut
Given the params of ExactInputSingleParams, it uses only one pool to swap exact an amountIn of tokenIn to tokenOut and return the amount of tokenOut from the swap.
It calls the swap function in the pool contract, the pool will transfer the tokenOut to the Router, and expect to receive the corresponding tokenIn in the swap callback function.
swapExactInput()
Params:
ExactInputParams params
Returns:
uint256 amountOut
Given the params of ExactInputParams, it uses only one or multiple pools that can be decoded from the path.
It calls the swap function in each pool contract that is decoded from the path param, and uses callback to handle transferring tokens.
Flow:
swapExactOutputSingle()
Params:
ExactOutputSingleParams params
Returns:
uint256 amountIn
Given the params of ExactOutputSingleParams, it uses only one pool to swap to get exact amountOut of tokenOut (or stop if price limit reaches).
swapExactOutput()
Params:
ExactOutputParams params
Returns:
uint256 amountIn
Given the params of ExactOutputParams, it uses one or multiple pools that can be decoded from the path.
It calls the swap function in each pool contract that is decoded from the path param, and uses callback to handle transferring tokens.
The list of pools in the path params should be in the reverse order, i.e the last pool first since we don't know the exact amount of token in to be used.
Flow:
Inherit from an ERC721 contract, it stores all positions of all liquidity providers and mint corresponding NFT.
Users can use the PositionManager to create & unlock pool, mint new position, add/remove liquidity to/from an existing position and burn their reinvestment tokens to receive back the LP fees.
It also inherits from Multicall contract, thus, users can make multiple function/method calls to the PositionManager in a single transaction.
All reinvestment tokens will be held in the contract, thus, it blocks anyone from transferring reinvestment tokens out. As a result, the contract can not support pools with any reinvestment tokens.
Params for the first time adding liquidity, mint new nft to sender
MintParams
address token0; // the token0 of the pool
address token1; // token1 of the pool, must make sure that token0 < token1
uint16 fee; // the pool's fee in bps
int24 tickLower; // the position's lower tick
int24 tickUpper; // the position's upper tick
int24[2] ticksPrevious; // the nearest tick that has been initialized and lower than or equal to the tickLower and tickUpper, use to help insert the tickLower and tickUpper if haven't initialized
uint256 amount0Desired; // the desired amount for token0
uint256 amount1Desired; // the desired amount for token1
uint256 amount0Min; // min amount of token 0 to add
uint256 amount1Min; // min amount of token 1 to add
address recipient; // the owner of the position
uint256 deadline; // time that the transaction will be expired
Params for adding liquidity to the existing position
IncreaseLiquidityParams
uint256 tokenId // id of the position to increase its liquidity
int24[2] ticksPrevious // the nearest tick that has been initialized and lower than or equal to the tickLower and tickUpper, use to help insert the tickLower and tickUpper if haven't initialized. Only needed if the position has been closed and the owner wants to add more liquidity
uint256 amount0Desired // the desired amount for token0
uint256 amount1Desired // the desired amount for token1
uint256 amount0Min // min amount of token 0 to add
uint256 amount1Min // min amount of token 1 to add
uint256 deadline // time that the transaction will be expired
Params for remove liquidity from the existing position
RemoveLiquidityParams
uint256 tokenId // id of the position to remove its liquidity
uint256 amount0Min // min amount of token 0 to receive
uint256 amount1Min // min amount of token 1 to receive
uint256 deadline // time that the transaction will be expired
Burn the rTokens to get back token0 + token1 as fees
BurnRTokenParams
uint256 tokenId // id of the position to burn r token
uint256 amount0Min // min amount of token 0 to receive
uint256 amount1Min // min amount of token 1 to receive
uint256 deadline // time that the transaction will be expired
createAndUnlockPoolIfNecessary()
Params:
address token0;
address token1;
uint16 fee;
uint160 currentSqrtP
Returns:
address pool // deployed pool given the set of params
Use this function to create & unlock a pool if needed given (token0, token1, fee) params and the initial sqrt price.
Required: token0 < token1
mint()
Params:
MintParams params
Returns:
uint256 tokenId;
uint128 liquidity,
uint256 amount0,
uint256 amount1
Call the _addLiquidity function in the LiquidityHelper contract with the data from *params.
It mints a new NFT token represents the position to the recipient, stores the position data and pool information.
addLiquidity()
Params:
IncreaseLiquidityParams params
Returns:
uint128 liquidity,
uint256 amount0,
uint256 amount1,
uint256 additionalRTokenOwed
Call the _addLiquidity function in the LiquidityHelper contract with the data from params to add more liquidity to a given position (i.e tokenId). Calculate and update the additional reinvestment tokens that the position should have earned.
removeLiquidity()
Params:
RemoveLiquidityParams params
Returns:
uint256 amount0,
uint256 amount1,
uint256 additionalRTokenOwed
Call the burn function in the pool contract with the data from params to remove liquidity and get back 2 tokens. Calculate and update the additional reinvestment tokens that the position should have earned.
burnRTokens()
Params:
BurnRTokenParams params
Returns:
uint256 rTokenQty,
uint256 amount0,
uint256 amount1
Call the burnRTokens function in the pool contract to burn all reinvestment tokens from the position and get back 2 tokens. Return the amount of reinvestment tokens to burn and expected amounts of 2 tokens to receive
syncFeeGrowth()
Params:
uint256 tokenId
Returns:
uint256 additionalRTokenOwed
Call the tweakPosZeroLiq function in the pool contract to sync fee growth in order to have the latest data for the reinvestment tokens, it should be called before calling the burnRTokens() function.
tokenURI()
, getApproved()
, _approve()
, _getAndIncrementNonce()
Overriding functions for the inherited ERC721 and permit contracts.
Inherits BasePositionManager and adds the anti-snipping attack feature into addLiquidity, removeLiquidity and syncFeeGrowth functions.
Reinvestment tokens of a position will be locked and vested to prevent LPs from adding then removing liquidity within a small period of time.
The motivation, mechanism and formula for Anti-Snipping Attack can be found here. The AntiSnippingAttack library will be of interest as well.
The goal is to accurately account a position's accured fees accured and duration for which it is active. A position is defined to be active if the current pool tick lies within the lower and upper ticks of the position.
The feeGrowthGlobal
and secondsPerLiquidityGlobal
variables represent the total amount for 1 unit of unbounded liquidity.
The outside value (feeGrowthOutside
and secondsPerLiquidityOutside
) for a tick represents the accumulated value relative to the currentTick. By definition, we can visually represent it to be as such:
When a tick is initialized, all growth is assumed to happen below it. Hence, the outside value is initialized to the following values under these cases:
outside value := global value
outside value := 0
Due to the definition of the outside value, a tick's outside value is reversed whenever the pool tick crosses it. Specifically, outside value := global value - outside value
.
When swapping downtick, the current tick is further decremented by 1. This is to ensure a tick's outside value is interpreted correctly.
swapData.currentTick = willUpTick ? tempNextTick : tempNextTick - 1;
The current tick can be
tickLower's outside value - tickUpper's outside value
global value - (lower + upper tick's outside values)
tickUpper's outside value - tickLower's outside value
To represent liquidity mapping, Kyber Elastic uses linked list, the linked list always starts by MIN_TICK and ends by MAX_TICK.
The pool also need to track to the highest initialized tick which is lower than or equal to currentTick (aka nearestCurrentTick
).
For example:
[MIN_TICK, MAX_TICK]
andnearestCurrentTick
will be MIN_TICK.[-5, 10]
, the linked list will be [MIN_TICK, -5, 10, MAX_TICK]
and nearestCurrentTick
will be -5.[0, 100]
, the linked list will be [MIN_TICK, -5, 0, 10, 100, MAX_TICK]
and nearestCurrentTick
will be 0.nearestCurrentTick
will be 10[-5, 10]
, the linked list will be [MIN_TICK, 0, 100, MAX_TICK]
andnearestCurrentTick
will be 0.Kyber Elastic does not take fee in forms of token0 and token1, the fee will be both tokens and reinvested into tick range from [0, infinity]
baseL
is the liquidity from lp provider and reinvestL
is the liquidity from the feereinvestL
, so we create reinvestment token to represent the proportion of user in reinvestL
.reinvestL
by baseL
. The formula to calculate mintQty is at ReinvestmentMath.calcrMintQty