owned this note
owned this note
Published
Linked with GitHub
# Core Libraries Documentation
## BaseSplitCodeFactory
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](https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/solidity-utils/contracts/helpers/BaseSplitCodeFactory.sol). 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.
---
## CodeDeployer
Taken from [Balancer Labs's solidity utils repo](https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/solidity-utils/contracts/helpers/CodeDeployer.sol). Imported and used by the [`BaseSplitCodeFactory`](#BaseSplitCodeFactory) contract to handle deployment.
---
## FullMath
Taken from [https://xn--2-umb.com/21/muldiv](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`](#mulDivFloor), but rounded up.
---
## LinkedList
A doubly linked list to be used for tick management.
### Struct: Data
| 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-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-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()`](#init).
| Field | Type | Explanation |
| -------- | -------- | -------- |
| `self` | `mapping(int24 => Data)` | A mapping of `int24` values to the [`Data`](#Struct-Data) struct|
| `removedValue` | `int24` | value to be removed |
---
## LiqDeltaMath
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 |
---
## MathConstants
Contains constants commonly used by multiple files.
---
## QtyDeltaMath
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`.
#### Input
| 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 |
#### Output
| 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`.
#### Input
| 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 |
#### Output
| 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.
---
## QuadMath
### `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](https://github.com/dynamic-amm/smart-contracts/blob/master/contracts/libraries/MathExt.sol#L36-L48). Calculates the square root of a value using the Babylonian method.
---
## ReinvestmentMath
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 |
---
## SafeCast
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`.
---
## SwapMath
Contains the logic needed for computing swap input / output amounts and fees. The primary function to look at is [`computeSwapStep`](#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.
#### Inputs
| 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 |
#### Outputs
| 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 |
#### Note
`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`](#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 |
---
## TickMath
Contains functions for computing square root prices from ticks and vice versa. Adapted from [Uniswap V3's TickMath library](https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/TickMath.sol).
### Constants
| 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. |
---
# Core Contracts Documentation
## Factory
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.
#### Input
| 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 |
#### Output
| 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:
1. Pool already exists
2. Invalid swap fee (tickDistance is zero)
3. Invalid token arguments
#### Input
| 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 |
#### Output
| 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`](#configMaster). Can only be changed by `configMaster`.
| Field | Type | Explanation |
| ---- | ----------- | ------ |
| `_configMaster` | `address` | new config master address |
### `enableWhitelist()`
Sets [`whitelistDisabled`](#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`](#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`](#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 |
---
## Pool
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.
#### Input
| Field | Type | Explanation |
| ---- | ----------- | ------ |
| `initialSqrtP` | `uint160` | Initial sqrt price, multiplied by $2^{96}$ |
| `data` | `bytes` | Data, if any, to be passed into the callback function |
#### Output
| 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](#burnRTokens) in exchange for token0 and token1.
#### Input
| 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 |
#### Output
| 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](#burnRTokens) in exchange for token0 and token1.
#### Input
| Field | Type | Explanation |
| ---- | ----------- | ------ |
| `tickLower` | `int24` | position's lower tick |
| `tickUpper` | `int24` | position's upper tick |
| `qty` | `uint128` | Liquidity quantity to burn |
#### Output
| 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.
#### Input
| 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.
#### Output
| 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.
#### Input
| Field | Type | Explanation |
| ---- | ----------- | ------ |
| `tickLower` | `int24` | The position's lower tick |
| `tickUpper` | `int24` | The position's upper tick |
#### Output
| 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.
#### Input
| 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 |
##### Note
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` |
#### Output
| 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.
#### Input
| 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 |
---
## PoolStorage
Contains all variables and getter methods to be used by the Pool contract. Inherited by [PoolTickState](#PoolTicksState).
### `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. <br/> [Appendix-A](#Appendix-A-Range-Mechanism) |
| `secondsPerLiquidityOutside` | `uint128` | seconds spent on the other side of the tick relative to the current tick. <br/> [Appendix-A](#Appendix-A-Range-Mechanism) |
### `initializedTicks()`
Returns the previous and next initialized ticks from the specified tick.
#### Note
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.
#### Inputs
| Field | Type | Explanation |
| ---- | ----------- | ------ |
| `owner` | `address` | position owner |
| `tickLower` | `int24` | position's lower tick |
| `tickUpper` | `int24` | position's upper tick |
#### Outputs
| 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](##Global-value).
### `getSecondsPerLiquidityData()`
| Field | Type | Explanation |
| ---- | ----------- | ------ |
| `secondsPerLiquidityGlobal` | `uint128` | all-time seconds per unit of liquidity of the pool. More information can be found [here](##Global-value) |
| `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.
#### Input
| Field | Type | Explanation |
| ---- | ----------- | ------ |
| `tickLower` | `int24` | a lower tick |
| `tickUpper` | `int24` | an upper tick |
#### Output
| 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](#Calculating-value-inside-ticks) |
### `_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.
---
## PoolTicksState
Inherits [PoolStorage](#PoolStorage). Contains functions for updating a tick's, position's or pool's state.
<!-- ### struct: UpdatePositionData
| Field | Type | Explanation |
| ---- | ----------- | ------ |
| `owner` | `address` | position owner |
| `tickLower` | `int24` | position's lower tick |
| `tickUpper` | `int24` | position's upper tick |
| `tickLowerPrevious` | `int24` | the expected nearest initialized tick that is <= `tickLower`|
| `tickUpperPrevious` | `int24` | the expected nearest initialized tick that is <= `tickLower`|
| `liquidityDelta` | `int128` | any change in liquidity | -->
### `_updatePosition()`
Calls [`_updateTick`](#_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()`](#_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](#Crossing-ticks)), 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).
### `_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`.
---
# Oracle Contracts
## Pool Oracle
### `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 |
# Periphery Base Contracts
## DeadlineValidation
Validate if the block timestamp has not reached the deadline yet, use for transactions with a deadline.
### Modifier: `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.
---
## ERC721Permit
Nonfungible tokens that support an approve via signature, i.e. permit for ERC721.
---
## ImmutableRouterStorage
Immutable variables that are used by Periphery contracts.
### Immutables
| Field | Type | Explanation |
| -------- | -------- | -------- |
| `factory` | `address` | [Factory](#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](#Factory) |
## RouterTokenHelper
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 |
---
## RouterTokenHelperWithFee
Inherits [RouteTokenHelper](#RouterTokenHelper). 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 |
---
## Multicall
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.
#### Input
| Field | Type | Explanation |
| -------- | -------- | -------- |
| `data` | `bytes[]` | encoded function data for each of the calls to make to this contract |
#### Output
| Field | Type | Explanation |
| -------- | -------- | -------- |
| `results` | `bytes[]` | results from each of the calls passed in |
---
## LiquidityHelper
A helper contract to handle liquidity related actions, including mint/add/remove liquidity.
### Struct: AddLiquidityParams
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 |
### Struct: CallbackData
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](#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*.
#### Input
| Type | Explanation |
| -------- | -------- |
| [`AddLiquidityParams`](#Struct-AddLiquidityParams) | Parameters for addiing liquidity to a pool |
#### Output
| 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](#Struct-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 |
---
# Periphery Libraries Contracts
## AntiSnippingAttack
The motivation and explanation of the mechanism can be found [here](https://docs.google.com/document/d/1F50RWQRRyaNxnW5RvKgw09fN2FofIVLVccijgcOt-Iw/edit#heading=h.trv8zmis8u4c). The function containing the bulk of the logic is [`update()`](#update).
### Struct: Data
| 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](#Struct-Data1) values for a new position. The time variables are set to the current timestamp, while `feesLocked` is set to zero.
### `update()`
Updates [Data](#Struct-Data1) 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.
#### Formula
$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()`](#calcFeeProportions)
$t_{unlock} = \frac{(t_{lock} + t_{target}) * (BPS - claimBps_{new}) * fee_{collect} + t_{unlock} * (BPS - claimBps_{current}) * fee_{locked}}{fee_{lock} * BPS}$
- If adding liquidity, update $t_{lock} = ceil(\frac{max(t_{lock}, t_{now} - t_{target})*L + t_{now} * \Delta{L}}{L + \Delta{L}})$
- If removing liquidity,
- $fee_{burn} = fee_{harvest} * \frac{\Delta{L}}{L}$
- $fee_{harvest}$ -= $fee_{burn}$
#### Input
| Field | Type | Formula Variable | Explanation |
| ----- | ---- | ----------- | ------------ |
| `self` | [`Data`](#Struct-Data1) | 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 |
#### Output
| 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.
#### Formula
$fee_{harvest} = \frac{claimBps_{current}}{BPS} * fee_{locked} + \frac{claimBps_{new}}{BPS} * fee_{collect}$
$fee_{lock} = fee_{locked} + fee_{collect} - fee_{harvest}$
#### Input
| 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 |
#### Output
| 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 |
---
## BytesLib
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.
---
## LiquidityMath
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
---
## PathHelper
Functions for manipulating path data for multihop swaps
### Variables
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.
---
## PoolAddress
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.
---
## PoolTicksCounter
### `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.
---
## TokenHelper
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**.
---
# Periphery Core Contracts
## Router
The Router contract to handle swapping.
### Struct: ExactInputSingleParams
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
### Struct: ExactInputParams
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
### Struct: ExactOutputSingleParams
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
### Struct: ExactOutputParams
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:
- Swap path: *tokenIn -> token0 -> token1 -> ... -> tokenOut*.
- Call the first pool to borrow **token0** to the **Router**, then transfer **tokenIn** from user's wallet to the first pool.
- Call the second pool to borrow **token1** to the **Router**, then transfer **token0** from the **Router** to the second pool.
- Repeat the action until the last pool, and transfer **tokenOut** directly to the **recipient**.
### `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).
- Call the **swap** function in the pool contract.
- The pool transfers the **tokenOut** to the **recipient**, and make the swap callback.
- The **Router** transfer the corresponding **tokenIn** from user's wallet to the pool.
The required amount of **tokenIn** should not be greater than **maxAmountIn**.
### `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:
- Origial swap path: *tokenIn -> token0 -> token1 -> ... -> tokenN -> tokenOut*.
- Reverse swap path: *tokenOut -> tokenN -> ... -> token1 -> token0 -> tokenIn*.
- Consider as we are swapping from **amountOut** of **tokenOut** to **tokenIn**.
---
## BasePositionManager
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.
### Struct: MintParams
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
### Struct: IncreaseLiquidityParams
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
### Struct: RemoveLiquidityParams
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
### Struct: BurnRTokenParams
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.
### Functions: `tokenURI()`, `getApproved()`, `_approve()`, `_getAndIncrementNonce()`
Overriding functions for the inherited ERC721 and permit contracts.
---
## AntiSnipAttackPositionManager
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](https://docs.google.com/document/d/1F50RWQRRyaNxnW5RvKgw09fN2FofIVLVccijgcOt-Iw/edit#heading=h.trv8zmis8u4c). The [AntiSnippingAttack library](#AntiSnippingAttack) will be of interest as well.
___
# Appendix
## Appendix A: Range Mechanism
### Objective
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.
### Global value
The `feeGrowthGlobal` and `secondsPerLiquidityGlobal` variables represent the total amount for 1 unit of unbounded liquidity.
![](https://i.imgur.com/DoPB569.png)
### Outside value
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:
- tick <= currentTick ![](https://i.imgur.com/IW8y1Gd.png)
- tick > currentTick ![](https://i.imgur.com/X0uXxvB.png)
#### Initialization
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:
- tick <= currentTick: `outside value := global value`
- tick > currentTick: `outside value := 0`
### Crossing ticks
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`.
#### Note
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;`
### Calculating value inside ticks
The current tick can be
1. below a position (currentTick < lowerTick)
![](https://i.imgur.com/s3jWPgr.png)
The value inside can therefore be calculated as `tickLower's outside value - tickUpper's outside value`
2. within a position (lowerTick <= currentTick < upperTick)
![](https://i.imgur.com/pO9HPYb.png)
The value inside can therefore be calculated as `global value - (lower + upper tick's outside values)`
3. above a position (upperTick <= currentTick)
![](https://i.imgur.com/Yi8iwu0.png)
The value inside can therefore be calculated as `tickUpper's outside value - tickLower's outside value`
## Appendix B: Tick-range Mechanism
- 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:
- the pool is initalized at tick 5, the linked list will be `[MIN_TICK, MAX_TICK]` and`nearestCurrentTick` will be MIN_TICK.
- A adds liquidity at tick `[-5, 10]`, the linked list will be `[MIN_TICK, -5, 10, MAX_TICK]` and `nearestCurrentTick` will be -5.
- C adds liquidity at tick `[0, 100]`, the linked list will be `[MIN_TICK, -5, 0, 10, 100, MAX_TICK]` and `nearestCurrentTick` will be 0.
- B swaps and currentTick = 15, then `nearestCurrentTick` will be 10
- A remove all liquidity at tick `[-5, 10]`, the linked list will be `[MIN_TICK, 0, 100, MAX_TICK]` and`nearestCurrentTick` will be 0.
## Appendix C: Reinvest Mechanism
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 fee
- User can still earn fee from `reinvestL`, so we create **reinvestment token** to represent the proportion of user in `reinvestL`.
- Each time, users add/remove liquidity or cross a tick, we have to mint the reinvestment token equavalent to the increment of `reinvestL` by `baseL`. The formula to calculate mintQty is at `ReinvestmentMath.calcrMintQty`
- reinvestment token: after London hardfork, it is [costly](https://hackmd.io/@fvictorio/gas-costs-after-berlin) to warm up another contract. Therfore, we decided to merge the reinvestment token and pool contract and the pool contract will be inherited from ERC20.