Skip to main content

ButtonswapPair

Inherits: IButtonswapPair, ButtonswapERC20

State Variables

MINIMUM_LIQUIDITY

The smallest value that {IButtonswapERC20-totalSupply} can be.

After the first mint the total liquidity (represented by the liquidity token total supply) can never drop below this value. This is to protect against an attack where the attacker mints a very small amount of liquidity, and then donates pool tokens to skew the ratio. This results in future minters receiving no liquidity tokens when they deposit. By enforcing a minimum liquidity value this attack becomes prohibitively expensive to execute.

uint256 public constant MINIMUM_LIQUIDITY = 10 ** 3;

BPS

Denominator for basis points.

uint256 private constant BPS = 10_000;

movingAverageWindow

The duration for which the moving average is calculated for.

uint32 public movingAverageWindow;

maxVolatilityBps

Numerator (over 10_000) of the threshold when price volatility triggers maximum single-sided timelock duration.

uint16 public maxVolatilityBps;

minTimelockDuration

How long the minimum singled-sided timelock lasts for.

uint32 public minTimelockDuration;

maxTimelockDuration

How long the maximum singled-sided timelock lasts for.

uint32 public maxTimelockDuration;

maxSwappableReservoirLimitBps

Numerator (over 10_000) of the fraction of the pool balance that acts as the maximum limit on how much of the reservoir can be swapped in a given timeframe.

uint16 public maxSwappableReservoirLimitBps;

swappableReservoirGrowthWindow

How much time it takes for the swappable reservoir value to grow from nothing to its maximum value.

uint32 public swappableReservoirGrowthWindow;

factory

The address of the {ButtonswapFactory} instance used to create this Pair.

Set to msg.sender in the Pair constructor.

address public immutable factory;

token0

The address of the first sorted token.

address public immutable token0;

token1

The address of the second sorted token.

address public immutable token1;

pool0Last

The active token0 liquidity amount following the last swap. This value is used to determine active liquidity balances after potential rebases until the next future swap.

uint112 internal pool0Last;

pool1Last

The active token1 liquidity amount following the last swap. This value is used to determine active liquidity balances after potential rebases until the next future swap.

uint112 internal pool1Last;

blockTimestampLast

The timestamp of the block that the last swap occurred in.

uint32 internal blockTimestampLast;

price0CumulativeLast

The time-weighted average price of the Pair. The price is of token0 in terms of token1.

The price is represented as a UQ112x112 to maintain precision. Consequently this value must be divided by 2^112 to get the actual price. Because of the time weighting, price0CumulativeLast must also be divided by the total Pair lifetime to get the average price over that time period.

uint256 public price0CumulativeLast;

price1CumulativeLast

The time-weighted average price of the Pair. The price is of token1 in terms of token0.

The price is represented as a UQ112x112 to maintain precision. Consequently this value must be divided by 2^112 to get the actual price. Because of the time weighting, price1CumulativeLast must also be divided by the total Pair lifetime to get the average price over that time period.

uint256 public price1CumulativeLast;

movingAveragePrice0Last

The value of movingAveragePrice0 at the time of the last swap.

uint256 internal movingAveragePrice0Last;

singleSidedTimelockDeadline

The timestamp for when the single-sided timelock concludes. The timelock is initiated based on price volatility of swaps over the last movingAverageWindow, and can be extended by new swaps if they are sufficiently volatile. The timelock protects against attempts to manipulate the price that is used to valuate the reservoir tokens during single-sided operations. It also guards against general legitimate volatility, as it is preferable to defer single-sided operations until it is clearer what the market considers the price to be.

uint120 public singleSidedTimelockDeadline;

swappableReservoirLimitReachesMaxDeadline

The timestamp by which the amount of reservoir tokens that can be exchanged during a single-sided operation reaches its maximum value. This maximum value is not necessarily the entirety of the reservoir, instead being calculated as a fraction of the corresponding token's active liquidity.

uint120 public swappableReservoirLimitReachesMaxDeadline;

isPaused

Whether or not the pair is isPaused (paused = 1, unPaused = 0). When paused, all operations other than dual-sided burning LP tokens are disabled.

uint8 internal isPaused;

unlocked

Value to track the state of the re-entrancy guard.

uint8 private unlocked = 1;

Functions

lock

Guards against re-entrancy.

modifier lock();

singleSidedTimelock

Prevents certain operations from being executed if the price volatility induced timelock has yet to conclude.

modifier singleSidedTimelock();

checkPaused

Prevents operations from being executed if the Pair is currently paused.

modifier checkPaused();

sendOrRefundFee

Called whenever an LP wants to burn their LP tokens to make sure they get their fair share of fees. If feeTo is defined, balanceOf(address(this)) gets transferred to feeTo. If feeTo is not defined, balanceOf(address(this)) gets burned and the LP tokens all grow in value.

modifier sendOrRefundFee();

onlyFactory

Prevents operations from being executed if the caller is not the factory.

modifier onlyFactory();

constructor

constructor();

name

Returns the name of the token.

function name() external view override(ButtonswapERC20, IButtonswapERC20) returns (string memory _name);

Returns

NameTypeDescription
_namestringThe token name

symbol

Returns the symbol of the token, usually a shorter version of the name.

function symbol() external view override(ButtonswapERC20, IButtonswapERC20) returns (string memory _symbol);

Returns

NameTypeDescription
_symbolstringThe token symbol

_mintFee

Always mints liquidity equivalent to 1/6th of the growth in sqrt(k) and allocates to address(this) If there isn't a feeTo address defined, these LP tokens will get burned this 1/6th gets reallocated to LPs

function _mintFee(uint256 pool0, uint256 pool1, uint256 pool0New, uint256 pool1New) internal;

Parameters

NameTypeDescription
pool0uint256The token0 active liquidity balance at the start of the ongoing swap
pool1uint256The token1 active liquidity balance at the start of the ongoing swap
pool0Newuint256The token0 active liquidity balance at the end of the ongoing swap
pool1Newuint256The token1 active liquidity balance at the end of the ongoing swap

_updatePriceCumulative

Updates price0CumulativeLast and price1CumulativeLast based on the current timestamp.

function _updatePriceCumulative(uint256 pool0, uint256 pool1) internal;

Parameters

NameTypeDescription
pool0uint256The token0 active liquidity balance at the start of the ongoing swap
pool1uint256The token1 active liquidity balance at the start of the ongoing swap

_closestBound

Refer to closest-bound-math.md for more detail.

function _closestBound(uint256 poolALower, uint256 poolB, uint256 _poolALast, uint256 _poolBLast)
internal
pure
returns (uint256 closestBound);

Parameters

NameTypeDescription
poolALoweruint256The lower bound for the active liquidity balance of the non-fixed token
poolBuint256The active liquidity balance of the fixed token
_poolALastuint256The active liquidity balance at the end of the last swap for the non-fixed token
_poolBLastuint256The active liquidity balance at the end of the last swap for the fixed token

Returns

NameTypeDescription
closestBounduint256The bound for the active liquidity balance of the non-fixed token that produces a price ratio closest to last swap price

_getLiquidityBalances

Refer to liquidity-balances-math.md for more detail.

function _getLiquidityBalances(uint256 total0, uint256 total1) internal view returns (LiquidityBalances memory lb);

Parameters

NameTypeDescription
total0uint256The total amount of token0 held by the Pair
total1uint256The total amount of token1 held by the Pair

Returns

NameTypeDescription
lbLiquidityBalancesThe current active and inactive liquidity balances

_updateSingleSidedTimelock

Calculates current price volatility and initiates a timelock scaled to the volatility size. This timelock prohibits single-sided operations from being executed until enough time has passed for the timelock to conclude. This protects against attempts to manipulate the price that the reservoir is valued at during single-sided operations.

function _updateSingleSidedTimelock(uint256 _movingAveragePrice0, uint112 pool0New, uint112 pool1New) internal;

Parameters

NameTypeDescription
_movingAveragePrice0uint256The current movingAveragePrice0 value
pool0Newuint112The token0 active liquidity balance at the end of the ongoing swap
pool1Newuint112The token1 active liquidity balance at the end of the ongoing swap

_getSwappableReservoirLimit

Calculates the current limit on the number of reservoir tokens that can be exchanged during a single-sided operation. This is based on corresponding active liquidity size and time since and size of the last single-sided operation.

function _getSwappableReservoirLimit(uint256 poolA) internal view returns (uint256 swappableReservoir);

Parameters

NameTypeDescription
poolAuint256The active liquidity balance for the non-zero reservoir token

Returns

NameTypeDescription
swappableReservoiruint256The amount of non-zero reservoir token that can be exchanged as part of a single-sided operation

getSwappableReservoirLimit

Returns the current limit on the number of reservoir tokens that can be exchanged during a single-sided mint/burn operation.

function getSwappableReservoirLimit() external view returns (uint256 swappableReservoirLimit);

Returns

NameTypeDescription
swappableReservoirLimituint256The amount of reservoir token that can be exchanged

_updateSwappableReservoirDeadline

Updates the value of swappableReservoirLimitReachesMaxDeadline which is the time at which the maximum amount of inactive liquidity tokens can be exchanged during a single-sided operation.

Assumes swappedAmountA is less than or equal to maxSwappableReservoirLimit

function _updateSwappableReservoirDeadline(uint256 poolA, uint256 swappedAmountA) internal;

Parameters

NameTypeDescription
poolAuint256The active liquidity balance for the non-zero reservoir token
swappedAmountAuint256The amount of non-zero reservoir tokens that were exchanged during the ongoing single-sided operation

getIsPaused

Whether the Pair is currently paused

function getIsPaused() external view returns (bool _isPaused);

Returns

NameTypeDescription
_isPausedboolThe paused state

setIsPaused

Updates the pause state. This can only be called by the Factory address.

function setIsPaused(bool isPausedNew) external onlyFactory;

Parameters

NameTypeDescription
isPausedNewboolThe new value for isPaused

getLiquidityBalances

Get the current liquidity values.

function getLiquidityBalances()
external
view
returns (uint112 _pool0, uint112 _pool1, uint112 _reservoir0, uint112 _reservoir1, uint32 _blockTimestampLast);

Returns

NameTypeDescription
_pool0uint112The active token0 liquidity
_pool1uint112The active token1 liquidity
_reservoir0uint112The inactive token0 liquidity
_reservoir1uint112The inactive token1 liquidity
_blockTimestampLastuint32The timestamp of when the price was last updated

movingAveragePrice0

The current movingAveragePrice0 value, based on the current block timestamp.

This is the token0 price, time weighted to prevent manipulation. Refer to reservoir-valuation.md for more detail. The price is represented as a UQ112x112 to maintain precision. It is used to valuate the reservoir tokens that are exchanged during single-sided operations.

function movingAveragePrice0() public view returns (uint256 _movingAveragePrice0);

Returns

NameTypeDescription
_movingAveragePrice0uint256The current movingAveragePrice0 value

mint

Mints new liquidity tokens to to based on amountIn0 of token0 and amountIn1 oftoken1` deposited. Expects both tokens to be deposited in a ratio that matches the current Pair price.

The token deposits are deduced to be the delta between token balance before and after the transfers in order to account for unusual tokens. Refer to mint-math.md for more detail.

function mint(uint256 amountIn0, uint256 amountIn1, address to)
external
lock
checkPaused
sendOrRefundFee
returns (uint256 liquidityOut);

Parameters

NameTypeDescription
amountIn0uint256The amount of token0 that should be transferred in from the user
amountIn1uint256The amount of token1 that should be transferred in from the user
toaddressThe account that receives the newly minted liquidity tokens

Returns

NameTypeDescription
liquidityOutuint256THe amount of liquidity tokens minted

mintWithReservoir

Mints new liquidity tokens to to based on how much token0 or token1 has been deposited. The token transferred is the one that the Pair does not have a non-zero inactive liquidity balance for. Expects only one token to be deposited, so that it can be paired with the other token's inactive liquidity.

The token deposits are deduced to be the delta between token balance before and after the transfers in order to account for unusual tokens. Refer to mint-math.md for more detail.

function mintWithReservoir(uint256 amountIn, address to)
external
lock
checkPaused
singleSidedTimelock
sendOrRefundFee
returns (uint256 liquidityOut);

Parameters

NameTypeDescription
amountInuint256The amount of tokens that should be transferred in from the user
toaddressThe account that receives the newly minted liquidity tokens

Returns

NameTypeDescription
liquidityOutuint256THe amount of liquidity tokens minted

burn

Burns liquidityIn liquidity tokens to redeem to to the corresponding amountOut0 of token0 and amountOut1 of token1.

Refer to burn-math.md for more detail.

function burn(uint256 liquidityIn, address to)
external
lock
sendOrRefundFee
returns (uint256 amountOut0, uint256 amountOut1);

Parameters

NameTypeDescription
liquidityInuint256The amount of liquidity tokens to burn
toaddressThe account that receives the redeemed tokens

Returns

NameTypeDescription
amountOut0uint256The amount of token0 that the liquidity tokens are redeemed for
amountOut1uint256The amount of token1 that the liquidity tokens are redeemed for

burnFromReservoir

Burns liquidityIn liquidity tokens to redeem to to the corresponding amountOut0 of token0 and amountOut1 of token1. Only returns tokens from the non-zero inactive liquidity balance, meaning one of amountOut0 and amountOut1 will be zero.

Refer to burn-math.md for more detail.

function burnFromReservoir(uint256 liquidityIn, address to)
external
lock
checkPaused
singleSidedTimelock
sendOrRefundFee
returns (uint256 amountOut0, uint256 amountOut1);

Parameters

NameTypeDescription
liquidityInuint256The amount of liquidity tokens to burn
toaddressThe account that receives the redeemed tokens

Returns

NameTypeDescription
amountOut0uint256The amount of token0 that the liquidity tokens are redeemed for
amountOut1uint256The amount of token1 that the liquidity tokens are redeemed for

swap

Swaps one token for the other, taking amountIn0 of token0 and amountIn1 of token1 from the sender and sending amountOut0 of token0 and amountOut1 of token1 to to. The price of the swap is determined by maintaining the "K Invariant". A 0.3% fee is collected to distribute between liquidity providers and the protocol.

The token deposits are deduced to be the delta between the current Pair contract token balances and the last stored balances. Optional calldata can be passed to data, which will be used to confirm the output token transfer with to if to is a contract that implements the {IButtonswapCallee} interface. Refer to swap-math.md for more detail.

function swap(uint256 amountIn0, uint256 amountIn1, uint256 amountOut0, uint256 amountOut1, address to)
external
lock
checkPaused;

Parameters

NameTypeDescription
amountIn0uint256The amount of token0 that the sender sends
amountIn1uint256The amount of token1 that the sender sends
amountOut0uint256The amount of token0 that the recipient receives
amountOut1uint256The amount of token1 that the recipient receives
toaddressThe account that receives the swap output

setMovingAverageWindow

Updates the movingAverageWindow parameter of the pair. This can only be called by the Factory address. Refer to parameters.md for more detail.

function setMovingAverageWindow(uint32 newMovingAverageWindow) external onlyFactory;

Parameters

NameTypeDescription
newMovingAverageWindowuint32The new value for movingAverageWindow

setMaxVolatilityBps

Updates the maxVolatilityBps parameter of the pair. This can only be called by the Factory address. Refer to parameters.md for more detail.

function setMaxVolatilityBps(uint16 newMaxVolatilityBps) external onlyFactory;

Parameters

NameTypeDescription
newMaxVolatilityBpsuint16The new value for maxVolatilityBps

setMinTimelockDuration

Updates the minTimelockDuration parameter of the pair. This can only be called by the Factory address. Refer to parameters.md for more detail.

function setMinTimelockDuration(uint32 newMinTimelockDuration) external onlyFactory;

Parameters

NameTypeDescription
newMinTimelockDurationuint32The new value for minTimelockDuration

setMaxTimelockDuration

Updates the maxTimelockDuration parameter of the pair. This can only be called by the Factory address. Refer to parameters.md for more detail.

function setMaxTimelockDuration(uint32 newMaxTimelockDuration) external onlyFactory;

Parameters

NameTypeDescription
newMaxTimelockDurationuint32The new value for maxTimelockDuration

setMaxSwappableReservoirLimitBps

Updates the maxSwappableReservoirLimitBps parameter of the pair. This can only be called by the Factory address. Refer to parameters.md for more detail.

function setMaxSwappableReservoirLimitBps(uint16 newMaxSwappableReservoirLimitBps) external onlyFactory;

Parameters

NameTypeDescription
newMaxSwappableReservoirLimitBpsuint16The new value for maxSwappableReservoirLimitBps

setSwappableReservoirGrowthWindow

Updates the swappableReservoirGrowthWindow parameter of the pair. This can only be called by the Factory address. Refer to parameters.md for more detail.

function setSwappableReservoirGrowthWindow(uint32 newSwappableReservoirGrowthWindow) external onlyFactory;

Parameters

NameTypeDescription
newSwappableReservoirGrowthWindowuint32The new value for swappableReservoirGrowthWindow

Structs

LiquidityBalances

A set of liquidity values.

struct LiquidityBalances {
uint256 pool0;
uint256 pool1;
uint256 reservoir0;
uint256 reservoir1;
}