Fold Captive Staking
Introduction
All the validators that are connected to the Manifold relay can ONLY connect to the Manifold relay (for mevAuction). If there's a service outage (of the relay), Manifold needs to be able to cover the cost (of lost opportunity) for validators.
Stakers into the FOLDstaking.sol
contract are underwriting this risk (captive insurance) of missing out on blocks. The contract keeps track of the durations of each deposit. Rewards are paid individually to each depositor.
Staking FOLD tokens transfers LP deposit ownership to the FOLDstaking
contract. The contract's owners (msig) require the ability to permanently claim FOLD balances in the interest of captive insurance claims through the claimInsurance
function.
In exchange, LPs are rewarded for staking (in addition to swap fees), and the compounding of their deposits' accrued fees is automated. This serves to incentivize a maximum number of compounds at optimal times with regards to gas costs.
Multiple deposits may be made of several V3 positions. The duration of each deposit as well as its share of the total liquidity deposited in the vault (for that pair) determines how much the reward will be (it's paid from the WETH balance of the contract).
There is no necessity for a Keeper to continuously compound rewards; however, withdrawals, after initiation, are pro-rated over 14 days if they are above a certain percentage of the total liquidity in the pool (borrowing from the queue design of mevETH with some small adjustment to fit).
Materials and Methods
To become accustomed with the relevant contextual terrain for an undertaking of our scope, we've surveyed some existing work on the subject of "address[ing] the issue of attracting stable liquidity".
Case in point: https://docs.pangolin.exchange/faqs/understanding-sar
The formula therein for calculating rewards has a useful property: (position stake / total staked) x (stake duration / average stake duration)
The useful property is in the second half of the expression. Division prevents an overflow from occurring (in the worst-case scenario) because, otherwise, duration would keep increasing (potentially indefinitely), and eventually cause an overflow in the result of the expression.
When it comes to calculating rewards, specifically, we don't take into account the stake's entire duration, looping through each week on a need-to-count basis (we divide and conquer the problem of aggregating rewards). Claiming rewards or removing liquidity resets the deposit's timestamp to the current week (reducing its total rewards).
For a separate matter, we do factor in the average stake duration. The following property is inherited from the so-called "sunshine & rainbow" design doc: "you can only have 1 position per wallet; you can always add on top of your current position, but you can’t split your position into multiple pieces."
Contrarily, Bunni, a lit protocol (Liquidity Incentive Token), wraps UNIv3 NFTs into a fungible token balance. Each balance is tightly coupled to the price range (ticks) for said NFT. As such, Bunni is its own sort of aggregator using multiple fungible token balances for one depositor.
Analysis
On an individual basis, depositors may wish to decide the price range (ticks) for their own UNIv3 NFT. They can do this with FOLDstaking.sol
by creating the NFT in advance (on an external platform), then calling our deposit
function, which takes DepositParams
.
Choosing price ranges for the individual deposit automatically applies a vote to affect the deposits of stakers who show no personal preference for their own NFT. This is because we don't force (though we do encourage) our depositors to accept the responsibility of this choice.
Instead, by calling our third deposit
function (with the least number of parameters) they may accept the time-weighted median for the price range (which factors in the individual decisions of depositors for each pool, respectively).
It is not necessary for LPs to manually claim fees collected by a V3 pool and redeposit them to increase the liquidity of a deposit. Uniswap is designed to handle this automatically, ensuring that fees are continuously working to enhance the earning potential of LPs.
Bunni has a compound
function to increase the value of share tokens (ERC20 balances that each correspond to a key, which is a pool and a price range to go with it). FOLDstaking.sol
approaches rewards differently so there is no requirement for this.
The difference also relates to how Bunni pays rewards pro rata to depositors' contribution per price range (relative to the total liquidity for that price range). FOLDstaking.sol
pays rewards solely based on the duration of the deposit and the total size of the deposit (across all price ranges) relative to the total liquidity in the pool (again, across all price ranges).
Contents
Contents
- IUniswapV3PoolActions
- IUniswapV3PoolDerivedState
- IUniswapV3PoolEvents
- IUniswapV3PoolImmutables
- IUniswapV3PoolOwnerActions
- IUniswapV3PoolState
IUniswapV3PoolActions
Contains pool methods that can be called by anyone
Functions
initialize
Sets the initial price for the pool
Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value
function initialize(uint160 sqrtPriceX96) external;
Parameters
Name | Type | Description |
---|---|---|
sqrtPriceX96 | uint160 | the initial sqrt price of the pool as a Q64.96 |
mint
Adds liquidity for the given recipient/tickLower/tickUpper position
The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends on tickLower, tickUpper, the amount of liquidity, and the current price.
function mint(address recipient, int24 tickLower, int24 tickUpper, uint128 amount, bytes calldata data)
external
returns (uint256 amount0, uint256 amount1);
Parameters
Name | Type | Description |
---|---|---|
recipient | address | The address for which the liquidity will be created |
tickLower | int24 | The lower tick of the position in which to add liquidity |
tickUpper | int24 | The upper tick of the position in which to add liquidity |
amount | uint128 | The amount of liquidity to mint |
data | bytes | Any data that should be passed through to the callback |
Returns
Name | Type | Description |
---|---|---|
amount0 | uint256 | The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback |
amount1 | uint256 | The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback |
collect
Collects tokens owed to a position
Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity. Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.
function collect(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount0Requested,
uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
Parameters
Name | Type | Description |
---|---|---|
recipient | address | The address which should receive the fees collected |
tickLower | int24 | The lower tick of the position for which to collect fees |
tickUpper | int24 | The upper tick of the position for which to collect fees |
amount0Requested | uint128 | How much token0 should be withdrawn from the fees owed |
amount1Requested | uint128 | How much token1 should be withdrawn from the fees owed |
Returns
Name | Type | Description |
---|---|---|
amount0 | uint128 | The amount of fees collected in token0 |
amount1 | uint128 | The amount of fees collected in token1 |
burn
Burn liquidity from the sender and account tokens owed for the liquidity to the position
Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0
Fees must be collected separately via a call to #collect
function burn(int24 tickLower, int24 tickUpper, uint128 amount) external returns (uint256 amount0, uint256 amount1);
Parameters
Name | Type | Description |
---|---|---|
tickLower | int24 | The lower tick of the position for which to burn liquidity |
tickUpper | int24 | The upper tick of the position for which to burn liquidity |
amount | uint128 | How much liquidity to burn |
Returns
Name | Type | Description |
---|---|---|
amount0 | uint256 | The amount of token0 sent to the recipient |
amount1 | uint256 | The amount of token1 sent to the recipient |
swap
Swap token0 for token1, or token1 for token0
The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
Parameters
Name | Type | Description |
---|---|---|
recipient | address | The address to receive the output of the swap |
zeroForOne | bool | The direction of the swap, true for token0 to token1, false for token1 to token0 |
amountSpecified | int256 | The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative) |
sqrtPriceLimitX96 | uint160 | The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this value after the swap. If one for zero, the price cannot be greater than this value after the swap |
data | bytes | Any data to be passed through to the callback |
Returns
Name | Type | Description |
---|---|---|
amount0 | int256 | The delta of the balance of token0 of the pool, exact when negative, minimum when positive |
amount1 | int256 | The delta of the balance of token1 of the pool, exact when negative, minimum when positive |
flash
Receive token0 and/or token1 and pay it back, plus a fee, in the callback
The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback
Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling with 0 amount{0,1} and sending the donation amount(s) from the callback
function flash(address recipient, uint256 amount0, uint256 amount1, bytes calldata data) external;
Parameters
Name | Type | Description |
---|---|---|
recipient | address | The address which will receive the token0 and token1 amounts |
amount0 | uint256 | The amount of token0 to send |
amount1 | uint256 | The amount of token1 to send |
data | bytes | Any data to be passed through to the callback |
increaseObservationCardinalityNext
Increase the maximum number of price and liquidity observations that this pool will store
This method is no-op if the pool already has an observationCardinalityNext greater than or equal to the input observationCardinalityNext.
function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;
Parameters
Name | Type | Description |
---|---|---|
observationCardinalityNext | uint16 | The desired minimum number of observations for the pool to store |
IUniswapV3PoolDerivedState
Contains view functions to provide information about the pool that is computed rather than stored on the blockchain. The functions here may have variable gas costs.
Functions
observe
Returns the cumulative tick and liquidity as of each timestamp secondsAgo
from the current block timestamp
To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick, you must call it with secondsAgos = [3600, 0].
The time weighted average tick represents the geometric time weighted average price of the pool, in log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.
function observe(uint32[] calldata secondsAgos)
external
view
returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);
Parameters
Name | Type | Description |
---|---|---|
secondsAgos | uint32[] | From how long ago each cumulative tick and liquidity value should be returned |
Returns
Name | Type | Description |
---|---|---|
tickCumulatives | int56[] | Cumulative tick values as of each secondsAgos from the current block timestamp |
secondsPerLiquidityCumulativeX128s | uint160[] | Cumulative seconds per liquidity-in-range value as of each secondsAgos from the current block timestamp |
snapshotCumulativesInside
Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range
Snapshots must only be compared to other snapshots, taken over a period for which a position existed. I.e., snapshots cannot be compared if a position is not held for the entire period between when the first snapshot is taken and the second snapshot is taken.
function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)
external
view
returns (int56 tickCumulativeInside, uint160 secondsPerLiquidityInsideX128, uint32 secondsInside);
Parameters
Name | Type | Description |
---|---|---|
tickLower | int24 | The lower tick of the range |
tickUpper | int24 | The upper tick of the range |
Returns
Name | Type | Description |
---|---|---|
tickCumulativeInside | int56 | The snapshot of the tick accumulator for the range |
secondsPerLiquidityInsideX128 | uint160 | The snapshot of seconds per liquidity for the range |
secondsInside | uint32 | The snapshot of seconds per liquidity for the range |
IUniswapV3PoolEvents
Contains all events emitted by the pool
Events
Initialize
Emitted exactly once by a pool when #initialize is first called on the pool
Mint/Burn/Swap cannot be emitted by the pool before Initialize
event Initialize(uint160 sqrtPriceX96, int24 tick);
Parameters
Name | Type | Description |
---|---|---|
sqrtPriceX96 | uint160 | The initial sqrt price of the pool, as a Q64.96 |
tick | int24 | The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool |
Mint
Emitted when liquidity is minted for a given position
event Mint(
address sender,
address indexed owner,
int24 indexed tickLower,
int24 indexed tickUpper,
uint128 amount,
uint256 amount0,
uint256 amount1
);
Parameters
Name | Type | Description |
---|---|---|
sender | address | The address that minted the liquidity |
owner | address | The owner of the position and recipient of any minted liquidity |
tickLower | int24 | The lower tick of the position |
tickUpper | int24 | The upper tick of the position |
amount | uint128 | The amount of liquidity minted to the position range |
amount0 | uint256 | How much token0 was required for the minted liquidity |
amount1 | uint256 | How much token1 was required for the minted liquidity |
Collect
Emitted when fees are collected by the owner of a position
Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees
event Collect(
address indexed owner,
address recipient,
int24 indexed tickLower,
int24 indexed tickUpper,
uint128 amount0,
uint128 amount1
);
Parameters
Name | Type | Description |
---|---|---|
owner | address | The owner of the position for which fees are collected |
recipient | address | |
tickLower | int24 | The lower tick of the position |
tickUpper | int24 | The upper tick of the position |
amount0 | uint128 | The amount of token0 fees collected |
amount1 | uint128 | The amount of token1 fees collected |
Burn
Emitted when a position's liquidity is removed
Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect
event Burn(
address indexed owner,
int24 indexed tickLower,
int24 indexed tickUpper,
uint128 amount,
uint256 amount0,
uint256 amount1
);
Parameters
Name | Type | Description |
---|---|---|
owner | address | The owner of the position for which liquidity is removed |
tickLower | int24 | The lower tick of the position |
tickUpper | int24 | The upper tick of the position |
amount | uint128 | The amount of liquidity to remove |
amount0 | uint256 | The amount of token0 withdrawn |
amount1 | uint256 | The amount of token1 withdrawn |
Swap
Emitted by the pool for any swaps between token0 and token1
event Swap(
address indexed sender,
address indexed recipient,
int256 amount0,
int256 amount1,
uint160 sqrtPriceX96,
uint128 liquidity,
int24 tick
);
Parameters
Name | Type | Description |
---|---|---|
sender | address | The address that initiated the swap call, and that received the callback |
recipient | address | The address that received the output of the swap |
amount0 | int256 | The delta of the token0 balance of the pool |
amount1 | int256 | The delta of the token1 balance of the pool |
sqrtPriceX96 | uint160 | The sqrt(price) of the pool after the swap, as a Q64.96 |
liquidity | uint128 | The liquidity of the pool after the swap |
tick | int24 | The log base 1.0001 of price of the pool after the swap |
Flash
Emitted by the pool for any flashes of token0/token1
event Flash(
address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1, uint256 paid0, uint256 paid1
);
Parameters
Name | Type | Description |
---|---|---|
sender | address | The address that initiated the swap call, and that received the callback |
recipient | address | The address that received the tokens from flash |
amount0 | uint256 | The amount of token0 that was flashed |
amount1 | uint256 | The amount of token1 that was flashed |
paid0 | uint256 | The amount of token0 paid for the flash, which can exceed the amount0 plus the fee |
paid1 | uint256 | The amount of token1 paid for the flash, which can exceed the amount1 plus the fee |
IncreaseObservationCardinalityNext
Emitted by the pool for increases to the number of observations that can be stored
observationCardinalityNext is not the observation cardinality until an observation is written at the index just before a mint/swap/burn.
event IncreaseObservationCardinalityNext(uint16 observationCardinalityNextOld, uint16 observationCardinalityNextNew);
Parameters
Name | Type | Description |
---|---|---|
observationCardinalityNextOld | uint16 | The previous value of the next observation cardinality |
observationCardinalityNextNew | uint16 | The updated value of the next observation cardinality |
SetFeeProtocol
Emitted when the protocol fee is changed by the pool
event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New);
Parameters
Name | Type | Description |
---|---|---|
feeProtocol0Old | uint8 | The previous value of the token0 protocol fee |
feeProtocol1Old | uint8 | The previous value of the token1 protocol fee |
feeProtocol0New | uint8 | The updated value of the token0 protocol fee |
feeProtocol1New | uint8 | The updated value of the token1 protocol fee |
CollectProtocol
Emitted when the collected protocol fees are withdrawn by the factory owner
event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);
Parameters
Name | Type | Description |
---|---|---|
sender | address | The address that collects the protocol fees |
recipient | address | The address that receives the collected protocol fees |
amount0 | uint128 | The amount of token0 protocol fees that is withdrawn |
amount1 | uint128 |
IUniswapV3PoolImmutables
These parameters are fixed for a pool forever, i.e., the methods will always return the same values
Functions
factory
The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface
function factory() external view returns (address);
Returns
Name | Type | Description |
---|---|---|
<none> | address | The contract address |
token0
The first of the two tokens of the pool, sorted by address
function token0() external view returns (address);
Returns
Name | Type | Description |
---|---|---|
<none> | address | The token contract address |
token1
The second of the two tokens of the pool, sorted by address
function token1() external view returns (address);
Returns
Name | Type | Description |
---|---|---|
<none> | address | The token contract address |
fee
The pool's fee in hundredths of a bip, i.e. 1e-6
function fee() external view returns (uint24);
Returns
Name | Type | Description |
---|---|---|
<none> | uint24 | The fee |
tickSpacing
The pool tick spacing
Ticks can only be used at multiples of this value, minimum of 1 and always positive e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ... This value is an int24 to avoid casting even though it is always positive.
function tickSpacing() external view returns (int24);
Returns
Name | Type | Description |
---|---|---|
<none> | int24 | The tick spacing |
maxLiquidityPerTick
The maximum amount of position liquidity that can use any tick in the range
This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
function maxLiquidityPerTick() external view returns (uint128);
Returns
Name | Type | Description |
---|---|---|
<none> | uint128 | The max amount of liquidity per tick |
IUniswapV3PoolOwnerActions
Contains pool methods that may only be called by the factory owner
Functions
setFeeProtocol
Set the denominator of the protocol's % share of the fees
function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;
Parameters
Name | Type | Description |
---|---|---|
feeProtocol0 | uint8 | new protocol fee for token0 of the pool |
feeProtocol1 | uint8 | new protocol fee for token1 of the pool |
collectProtocol
Collect the protocol fee accrued to the pool
function collectProtocol(address recipient, uint128 amount0Requested, uint128 amount1Requested)
external
returns (uint128 amount0, uint128 amount1);
Parameters
Name | Type | Description |
---|---|---|
recipient | address | The address to which collected protocol fees should be sent |
amount0Requested | uint128 | The maximum amount of token0 to send, can be 0 to collect fees in only token1 |
amount1Requested | uint128 | The maximum amount of token1 to send, can be 0 to collect fees in only token0 |
Returns
Name | Type | Description |
---|---|---|
amount0 | uint128 | The protocol fee collected in token0 |
amount1 | uint128 | The protocol fee collected in token1 |
IUniswapV3PoolState
These methods compose the pool's state, and can change with any frequency including multiple times per transaction
Functions
slot0
The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas when accessed externally.
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint8 feeProtocol,
bool unlocked
);
Returns
Name | Type | Description |
---|---|---|
sqrtPriceX96 | uint160 | The current price of the pool as a sqrt(token1/token0) Q64.96 value tick The current tick of the pool, i.e. according to the last tick transition that was run. This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick boundary. observationIndex The index of the last oracle observation that was written, observationCardinality The current maximum number of observations stored in the pool, observationCardinalityNext The next maximum number of observations, to be updated when the observation. feeProtocol The protocol fee for both tokens of the pool. Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0 is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee. unlocked Whether the pool is currently locked to reentrancy |
tick | int24 | |
observationIndex | uint16 | |
observationCardinality | uint16 | |
observationCardinalityNext | uint16 | |
feeProtocol | uint8 | |
unlocked | bool |
feeGrowthGlobal0X128
The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool
This value can overflow the uint256
function feeGrowthGlobal0X128() external view returns (uint256);
feeGrowthGlobal1X128
The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool
This value can overflow the uint256
function feeGrowthGlobal1X128() external view returns (uint256);
protocolFees
The amounts of token0 and token1 that are owed to the protocol
Protocol fees will never exceed uint128 max in either token
function protocolFees() external view returns (uint128 token0, uint128 token1);
liquidity
The currently in range liquidity available to the pool
This value has no relationship to the total liquidity across all ticks
function liquidity() external view returns (uint128);
ticks
Look up information about a specific tick in the pool
function ticks(int24 tick)
external
view
returns (
uint128 liquidityGross,
int128 liquidityNet,
uint256 feeGrowthOutside0X128,
uint256 feeGrowthOutside1X128,
int56 tickCumulativeOutside,
uint160 secondsPerLiquidityOutsideX128,
uint32 secondsOutside,
bool initialized
);
Parameters
Name | Type | Description |
---|---|---|
tick | int24 | The tick to look up |
Returns
Name | Type | Description |
---|---|---|
liquidityGross | uint128 | the total amount of position liquidity that uses the pool either as tick lower or tick upper, liquidityNet how much liquidity changes when the pool price crosses the tick, feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0, feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1, tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick, secondsOutside the seconds spent on the other side of the tick from the current tick, initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false. Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0. In addition, these values are only relative and must be used only in comparison to previous snapshots for a specific position. |
liquidityNet | int128 | |
feeGrowthOutside0X128 | uint256 | |
feeGrowthOutside1X128 | uint256 | |
tickCumulativeOutside | int56 | |
secondsPerLiquidityOutsideX128 | uint160 | |
secondsOutside | uint32 | |
initialized | bool |
tickBitmap
Returns 256 packed tick initialized boolean values. See TickBitmap for more information
function tickBitmap(int16 wordPosition) external view returns (uint256);
positions
Returns the information about a position by the position's key
function positions(bytes32 key)
external
view
returns (
uint128 _liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
Parameters
Name | Type | Description |
---|---|---|
key | bytes32 | The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper |
Returns
Name | Type | Description |
---|---|---|
_liquidity | uint128 | The amount of liquidity in the position, Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke, Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke, Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke, Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke |
feeGrowthInside0LastX128 | uint256 | |
feeGrowthInside1LastX128 | uint256 | |
tokensOwed0 | uint128 | |
tokensOwed1 | uint128 |
observations
Returns data about a specific observation index
You most likely want to use #observe() instead of this method to get an observation as of some amount of time ago, rather than at a specific index in the array.
function observations(uint256 index)
external
view
returns (uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128, bool initialized);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | The element of the observations array to fetch |
Returns
Name | Type | Description |
---|---|---|
blockTimestamp | uint32 | The timestamp of the observation, Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp, Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp, Returns initialized whether the observation has been initialized and the values are safe to use |
tickCumulative | int56 | |
secondsPerLiquidityCumulativeX128 | uint160 | |
initialized | bool |
INonfungiblePositionManager
Wraps Uniswap V3 positions in a non-fungible token interface which allows for them to be transferred and authorized.
Functions
positions
Returns the position information associated with a given token ID.
Throws if the token ID is not valid.
function positions(uint256 tokenId)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
uint24 fee,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
Parameters
Name | Type | Description |
---|---|---|
tokenId | uint256 | The ID of the token that represents the position |
Returns
Name | Type | Description |
---|---|---|
nonce | uint96 | The nonce for permits |
operator | address | The address that is approved for spending |
token0 | address | The address of the token0 for a specific pool |
token1 | address | The address of the token1 for a specific pool |
fee | uint24 | The fee associated with the pool |
tickLower | int24 | The lower end of the tick range for the position |
tickUpper | int24 | The higher end of the tick range for the position |
liquidity | uint128 | The liquidity of the position |
feeGrowthInside0LastX128 | uint256 | The fee growth of token0 as of the last action on the individual position |
feeGrowthInside1LastX128 | uint256 | The fee growth of token1 as of the last action on the individual position |
tokensOwed0 | uint128 | The uncollected amount of token0 owed to the position as of the last computation |
tokensOwed1 | uint128 | The uncollected amount of token1 owed to the position as of the last computation |
mint
Creates a new position wrapped in a NFT
Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized a method does not exist, i.e. the pool is assumed to be initialized.
function mint(MintParams calldata params)
external
payable
returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
Parameters
Name | Type | Description |
---|---|---|
params | MintParams | The params necessary to mint a position, encoded as MintParams in calldata |
Returns
Name | Type | Description |
---|---|---|
tokenId | uint256 | The ID of the token that represents the minted position |
liquidity | uint128 | The amount of liquidity for this position |
amount0 | uint256 | The amount of token0 |
amount1 | uint256 | The amount of token1 |
increaseLiquidity
Increases the amount of liquidity in a position, with tokens paid by the msg.sender
function increaseLiquidity(IncreaseLiquidityParams calldata params)
external
payable
returns (uint128 liquidity, uint256 amount0, uint256 amount1);
Parameters
Name | Type | Description |
---|---|---|
params | IncreaseLiquidityParams | tokenId The ID of the token for which liquidity is being increased, amount0Desired The desired amount of token0 to be spent, amount1Desired The desired amount of token1 to be spent, amount0Min The minimum amount of token0 to spend, which serves as a slippage check, amount1Min The minimum amount of token1 to spend, which serves as a slippage check, deadline The time by which the transaction must be included to effect the change |
Returns
Name | Type | Description |
---|---|---|
liquidity | uint128 | The new liquidity amount as a result of the increase |
amount0 | uint256 | The amount of token0 to acheive resulting liquidity |
amount1 | uint256 | The amount of token1 to acheive resulting liquidity |
decreaseLiquidity
Decreases the amount of liquidity in a position and accounts it to the position
function decreaseLiquidity(DecreaseLiquidityParams calldata params)
external
payable
returns (uint256 amount0, uint256 amount1);
Parameters
Name | Type | Description |
---|---|---|
params | DecreaseLiquidityParams | tokenId The ID of the token for which liquidity is being decreased, amount The amount by which liquidity will be decreased, amount0Min The minimum amount of token0 that should be accounted for the burned liquidity, amount1Min The minimum amount of token1 that should be accounted for the burned liquidity, deadline The time by which the transaction must be included to effect the change |
Returns
Name | Type | Description |
---|---|---|
amount0 | uint256 | The amount of token0 accounted to the position's tokens owed |
amount1 | uint256 | The amount of token1 accounted to the position's tokens owed |
collect
Collects up to a maximum amount of fees owed to a specific position to the recipient
function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1);
Parameters
Name | Type | Description |
---|---|---|
params | CollectParams | tokenId The ID of the NFT for which tokens are being collected, recipient The account that should receive the tokens, amount0Max The maximum amount of token0 to collect, amount1Max The maximum amount of token1 to collect |
Returns
Name | Type | Description |
---|---|---|
amount0 | uint256 | The amount of fees collected in token0 |
amount1 | uint256 | The amount of fees collected in token1 |
burn
Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens must be collected first.
function burn(uint256 tokenId) external payable;
Parameters
Name | Type | Description |
---|---|---|
tokenId | uint256 | The ID of the token that is being burned |
Events
IncreaseLiquidity
Emitted when liquidity is increased for a position NFT
Also emitted when a token is minted
event IncreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
Parameters
Name | Type | Description |
---|---|---|
tokenId | uint256 | The ID of the token for which liquidity was increased |
liquidity | uint128 | The amount by which liquidity for the NFT position was increased |
amount0 | uint256 | The amount of token0 that was paid for the increase in liquidity |
amount1 | uint256 | The amount of token1 that was paid for the increase in liquidity |
DecreaseLiquidity
Emitted when liquidity is decreased for a position NFT
event DecreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
Parameters
Name | Type | Description |
---|---|---|
tokenId | uint256 | The ID of the token for which liquidity was decreased |
liquidity | uint128 | The amount by which liquidity for the NFT position was decreased |
amount0 | uint256 | The amount of token0 that was accounted for the decrease in liquidity |
amount1 | uint256 | The amount of token1 that was accounted for the decrease in liquidity |
Collect
Emitted when tokens are collected for a position NFT
The amounts reported may not be exactly equivalent to the amounts transferred, due to rounding behavior
event Collect(uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1);
Parameters
Name | Type | Description |
---|---|---|
tokenId | uint256 | The ID of the token for which underlying tokens were collected |
recipient | address | The address of the account that received the collected tokens |
amount0 | uint256 | The amount of token0 owed to the position that was collected |
amount1 | uint256 | The amount of token1 owed to the position that was collected |
Structs
MintParams
struct MintParams {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
IncreaseLiquidityParams
struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
DecreaseLiquidityParams
struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
CollectParams
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
IUniswapV3Factory
The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and control over the protocol fees
Functions
owner
Returns the current owner of the factory
Can be changed by the current owner via setOwner
function owner() external view returns (address);
Returns
Name | Type | Description |
---|---|---|
<none> | address | The address of the factory owner |
feeAmountTickSpacing
Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled
A fee amount can never be removed, so this value should be hard coded or cached in the calling context
function feeAmountTickSpacing(uint24 fee) external view returns (int24);
Parameters
Name | Type | Description |
---|---|---|
fee | uint24 | The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee |
Returns
Name | Type | Description |
---|---|---|
<none> | int24 | The tick spacing |
getPool
Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist
tokenA and tokenB may be passed in either token0/token1 or token1/token0 order
function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool);
Parameters
Name | Type | Description |
---|---|---|
tokenA | address | The contract address of either token0 or token1 |
tokenB | address | The contract address of the other token |
fee | uint24 | The fee collected upon every swap in the pool, denominated in hundredths of a bip |
Returns
Name | Type | Description |
---|---|---|
pool | address | The pool address |
createPool
Creates a pool for the given two tokens and fee
tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments are invalid.
function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool);
Parameters
Name | Type | Description |
---|---|---|
tokenA | address | One of the two tokens in the desired pool |
tokenB | address | The other of the two tokens in the desired pool |
fee | uint24 | The desired fee for the pool |
Returns
Name | Type | Description |
---|---|---|
pool | address | The address of the newly created pool |
setOwner
Updates the owner of the factory
Must be called by the current owner
function setOwner(address _owner) external;
Parameters
Name | Type | Description |
---|---|---|
_owner | address | The new owner of the factory |
enableFeeAmount
Enables a fee amount with the given tickSpacing
Fee amounts may never be removed once enabled
function enableFeeAmount(uint24 fee, int24 tickSpacing) external;
Parameters
Name | Type | Description |
---|---|---|
fee | uint24 | The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6) |
tickSpacing | int24 | The spacing between ticks to be enforced for all pools created with the given fee amount |
Events
OwnerChanged
Emitted when the owner of the factory is changed
event OwnerChanged(address indexed oldOwner, address indexed newOwner);
Parameters
Name | Type | Description |
---|---|---|
oldOwner | address | The owner before the owner was changed |
newOwner | address | The owner after the owner was changed |
PoolCreated
Emitted when a pool is created
event PoolCreated(address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool);
Parameters
Name | Type | Description |
---|---|---|
token0 | address | The first token of the pool by address sort order |
token1 | address | The second token of the pool by address sort order |
fee | uint24 | The fee collected upon every swap in the pool, denominated in hundredths of a bip |
tickSpacing | int24 | The minimum number of ticks between initialized ticks |
pool | address | The address of the created pool |
FeeAmountEnabled
Emitted when a new fee amount is enabled for pool creation via the factory
event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing);
Parameters
Name | Type | Description |
---|---|---|
fee | uint24 | The enabled fee, denominated in hundredths of a bip |
tickSpacing | int24 | The minimum number of ticks between initialized ticks for pools created with the given fee |
IUniswapV3MintCallback
Any contract that calls IUniswapV3PoolActions#mint must implement this interface
Functions
uniswapV3MintCallback
Called to msg.sender
after minting liquidity to a position from IUniswapV3Pool#mint.
In the implementation you must pay the pool tokens owed for the minted liquidity. The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
function uniswapV3MintCallback(uint256 amount0Owed, uint256 amount1Owed, bytes calldata data) external;
Parameters
Name | Type | Description |
---|---|---|
amount0Owed | uint256 | The amount of token0 due to the pool for the minted liquidity |
amount1Owed | uint256 | The amount of token1 due to the pool for the minted liquidity |
data | bytes | Any data passed through by the caller via the IUniswapV3PoolActions#mint call |
IUniswapV3Pool
Inherits: IUniswapV3PoolImmutables, IUniswapV3PoolState, IUniswapV3PoolDerivedState, IUniswapV3PoolActions, IUniswapV3PoolOwnerActions, IUniswapV3PoolEvents
A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform to the ERC20 specification
The pool interface is broken up into many smaller pieces
Contents
TickMath
Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports prices between 2**-128 and 2**128
State Variables
MIN_TICK
The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2*-128*
int24 internal constant MIN_TICK = -887272;
MAX_TICK
The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
int24 internal constant MAX_TICK = -MIN_TICK;
MIN_SQRT_RATIO
The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
MAX_SQRT_RATIO
The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
Functions
getSqrtRatioAtTick
Calculates sqrt(1.0001^tick) * 2^96
Throws if |tick| > max tick
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96);
Parameters
Name | Type | Description |
---|---|---|
tick | int24 | The input tick for the above formula |
Returns
Name | Type | Description |
---|---|---|
sqrtPriceX96 | uint160 | A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) at the given tick |
getTickAtSqrtRatio
Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may ever return.
function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick);
Parameters
Name | Type | Description |
---|---|---|
sqrtPriceX96 | uint160 | The sqrt ratio for which to compute the tick as a Q64.96 |
Returns
Name | Type | Description |
---|---|---|
tick | int24 | The greatest tick for which the ratio is less than or equal to the input ratio |
FoldCaptiveStaking
Inherits: Owned
Author: CopyPaste
SPDX-License-Identifier: SSPL-1.0 Interfaces Libraries contracts
Staking contract for managing FOLD token liquidity on Uniswap V3
State Variables
initialized
bool public initialized;
TICK_UPPER
The max Tick of the position
int24 public constant TICK_UPPER = TickMath.MAX_TICK;
TICK_LOWER
The lower Tick of the position
int24 public constant TICK_LOWER = TickMath.MIN_TICK;
positionManager
The Canonical UniswapV3 Position Manager
INonfungiblePositionManager public immutable positionManager;
POOL
The FOLD <> {WETH, USDC} Liquidity Pool
IUniswapV3Pool public immutable POOL;
token0
token0 In terms of the Uniswap Pool
ERC20 public immutable token0;
token1
token1 in terms of the Uniswap Pool
ERC20 public immutable token1;
TOKEN_ID
The tokenId of the UniswapV3 position
uint256 public TOKEN_ID;
liquidityUnderManagement
Used for all rewards related tracking
uint256 public liquidityUnderManagement;
rewardsPerLiquidity
Used to keep track of rewards given per share
uint256 public rewardsPerLiquidity;
token0FeesPerLiquidity
For keeping track of position fees
uint256 public token0FeesPerLiquidity;
token1FeesPerLiquidity
For keeping track of positions fees
uint256 public token1FeesPerLiquidity;
depositCap
The cap on deposits in the pool in liquidity, set to 0 if no cap
uint256 public depositCap;
balances
mapping(address user => UserInfo info) public balances;
WETH9
The Canonical WETH address
WETH public immutable WETH9;
FOLD
ERC20 public immutable FOLD;
Functions
constructor
constructor(address _positionManager, address _pool, address _weth, address _fold);
Parameters
Name | Type | Description |
---|---|---|
_positionManager | address | The Canonical UniswapV3 PositionManager |
_pool | address | The FOLD Pool to Reward |
_weth | address | The address of WETH on the deployed chain |
_fold | address | The address of Fold on the deployed chain |
initialize
Initialize the contract by minting a small initial liquidity position
function initialize() public onlyOwner;
isInitialized
modifier isInitialized();
depositRewards
Allows anyone to add funds to the contract, split among all depositors
function depositRewards() public payable isInitialized;
receive
receive() external payable;
deposit
Allows a user to deposit liquidity into the pool
function deposit(uint256 amount0, uint256 amount1, uint256 slippage) external isInitialized;
Parameters
Name | Type | Description |
---|---|---|
amount0 | uint256 | The amount of token0 to deposit |
amount1 | uint256 | The amount of token1 to deposit |
slippage | uint256 | Slippage on deposit out of 1e18 |
compound
Compounds User Earned Fees back into their position
function compound() public isInitialized;
collectFees
User-specific function to collect fees on the singular position
function collectFees() public isInitialized;
collectRewards
User-specific Rewards for Protocol Rewards
function collectRewards() public isInitialized;
withdraw
Withdraws liquidity from the pool
function withdraw(uint128 liquidity) external isInitialized;
Parameters
Name | Type | Description |
---|---|---|
liquidity | uint128 | The amount of liquidity to withdraw |
collectPositionFees
Collects fees on the underling UniswapV3 Position
function collectPositionFees() internal;
setDepositCap
function setDepositCap(uint256 _newCap) public onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
_newCap | uint256 | The new deposit cap, measured in liquidity |
claimInsurance
Allows the owner to claim insurance in case of relay outage
function claimInsurance(uint128 liquidity) external onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
liquidity | uint128 | The amount of liquidity to claim |
Events
Initialized
event Initialized();
Deposit
event Deposit(address indexed user, uint256 amount0, uint256 amount1);
Withdraw
event Withdraw(address indexed user, uint128 liquidity);
RewardsDeposited
event RewardsDeposited(uint256 amount);
FeesCollected
event FeesCollected(address indexed user, uint256 fee0Owed, uint256 fee1Owed);
RewardsCollected
event RewardsCollected(address indexed user, uint256 rewardsOwed);
Compounded
event Compounded(address indexed user, uint128 liquidity, uint256 fee0Owed, uint256 fee1Owed);
InsuranceClaimed
event InsuranceClaimed(address indexed owner, uint256 amount0, uint256 amount1);
Errors
ZeroAddress
Custom Errors
error ZeroAddress();
AlreadyInitialized
error AlreadyInitialized();
NotInitialized
error NotInitialized();
ZeroLiquidity
error ZeroLiquidity();
WithdrawFailed
error WithdrawFailed();
WithdrawProRata
error WithdrawProRata();
DepositCapReached
error DepositCapReached();
Structs
UserInfo
struct UserInfo {
uint128 amount;
uint128 rewardDebt;
uint128 token0FeeDebt;
uint128 token1FeeDebt;
}