CronV1Pool

Uses Balancer math library for overflow/underflow checks on standard U256 containers. However, as many custom representations are used (i.e. non native word lengths) there are a number of explicit checks against the maximum of other word lengths. Furthermore there are unchecked operations (this code targets Solidity 0.7.x which didn't yet feature implicit arithmetic checks or have the 'unchecked' block feature) herein for reasons of efficiency or desired overflow. Wherever they appear they will be documented and accompanied with one of the following tags: - #unchecked - #overUnderFlowIntended Identified risks will be accompanied and described with the following tag: - #RISK

Conventions in the methods, variables and constants are as follows:

 Prefixes:

 - In constants, the prefix "Sn", where 1 <= n <= 4, denotes which slot the constant
   pertains too. There are four storage slots that are bitpacked. For example,
   "S2_OFFSET_ORACLE_TIMESTAMP" refers to the offset of the oracle timestamp in bit-
   packed storage slot 2.

 Suffixes:

 - The suffix of a variable name denotes the type contained within the variable.
   For instance "uint256 _incrementU96" is a 256-bit unsigned container representing
   the 96-bit value "_increment".
   In the case of "uint256 _balancerFeeDU1F18", the 256-bit unsigned container is
   representing a 19 digit decimal value with 18 fractional digits. In this scenario,
   the D=Decimal, U=Unsigned, F=Fractional.
   Finally, "uint128 valueU128F64" is a 128-bit container representing a 128-bit value
   with 64 fractional bits.

 - The suffix of a function name denotes what slot it is proprietary too as a
   matter of convention. While unchecked at run-time or by the compiler, the naming
   convention easily aids in understanding what slot a packed value is stored within.
   For instance the function "unpackFeeShiftS3" unpacks the fee shift from slot 3.
   If the value of slot 2 were passed to this method, the unpacked value would be
   incorrect.

Fee Points (FP) is a system used herein to calculate applicable fees. THESE ABSOLUTELY SHOULD NOT BE CONFUSED WITH BASIS POINTS--THEY ARE NOT BASIS POINTS! It consists of fees, such as a swap fee, expressed in FP. The swap fee is multiplied by the amount of token being swapped and divided by the total fee points (TOTAL_FP), which is 100,000, to obtain the fee. For instance, a swap fee of 0.050% can be realized as follows:

               token_in x FEE_BP
    swap_fee = -----------------
                    TOTAL_FP

                 token_in x 50
             = -----------------
                     100000_

POOL_ID

bytes32 POOL_ID

POOL_TYPE

enum ICronV1PoolEnums.PoolType POOL_TYPE

slot1

uint256 slot1

slot2

uint256 slot2

slot3

uint256 slot3

slot4

uint256 slot4

priceOracle

struct PriceOracle priceOracle

adminAddrMap

mapping(address => bool) adminAddrMap

partnerContractAddrMap

mapping(address => address) partnerContractAddrMap

feeAddr

address feeAddr

senderIsFactoryOwner

modifier senderIsFactoryOwner()

Ensure that the modified function is called by an address that is the factory owner.

Cannot be used on Balancer Vault callbacks (onJoin, onExit, onSwap) because msg.sender is the Vault address.

senderIsAdmin

modifier senderIsAdmin()

Ensures that the modified function is called by an address with administrator privileges.

Cannot be used on Balancer Vault callbacks (onJoin, onExit, onSwap) because msg.sender is the Vault address.

senderIsArbitragePartner

modifier senderIsArbitragePartner()

Ensures the modified function is called by an address with arbitrage partner privileges.

Cannot be used on Balancer Vault callbacks (onJoin, onExit, onSwap) because msg.sender is the Vault address.

poolNotPaused

modifier poolNotPaused()

Ensures that the modified function is not executed if the pool is currently paused.

constructor

constructor(contract IERC20 _token0Inst, contract IERC20 _token1Inst, contract IVault _vaultInst, string _poolName, string _poolSymbol, enum ICronV1PoolEnums.PoolType _poolType) public

Creates an instance of the Cron-Fi TWAMM pool. A Cron-Fi TWAMM pool features virtual order management and virtualized reserves. Liquidity is managed through an instance of BalancerPoolToken. The fees associated with the pool are configurable at run-time.

    Importantly, the OBI cannot be changed after instantiation. If a pool's OBI is inappropriate to the
    properties of the pair of tokens, it is recommended to create a new pool.

    In the event of a failure, the pool can be paused which bypasses computation of virtual orders and allows
    liquidity to be removed and long-term virtual orders to be withdrawn and refunded. Other operations are
    blocked.

    Management of the pool is performed by administrators who are able set gross swap fee amounts and
    aribtrage partner status.

    The pool factory owner is able to set the status of administrators, enable Cron-Fi fees, modify the
    Cron-Fi fee address, adjust the fee-split between Cron-Fi and liquidity providers, and enable Balancer
    fees.

    Arbitrage partners are able to set and update a contract address that lists their arbitrageur's addresses,
    which are able to swap at reduced fees as an incentive to provide better long-term order execution by
    adjusting the bonding curve to compensate for the effect of virtual orders. These partners perform
    accounting and capture a percentage of the trades or capture fees in another way which are periodically
    remitted to the pool, rewarding the liquidity providers. This may be thought of as a constructive pay for
    order flow or Maximal Extractable Value (MEV) recapture.

Parameters

onSwap

function onSwap(struct IPoolSwapStructs.SwapRequest _swapRequest, uint256 _currentBalanceTokenInU112, uint256 _currentBalanceTokenOutU112) external returns (uint256 amountOutU112)

Called by the vault when a user calls IVault.swap. Can be used to perform a Short-Term (ST) swap, Long-Term (LT) swap, or Partner swap ST swaps and Partner swaps behave like traditional Automated Market Maker atomic swaps (think Uniswap V2 swaps). LT swaps are virtual orders and behave differently, executing over successive blocks until their expiry. Each LT swap is assigned an order id that is logged in a LongTermSwap event and can also be fetched using getOrderIds for a given address. LT swaps can be withdrawn or cancelled through the IVault.exit function (see onExitPool documentation).

Parameters

Return Values

onJoinPool

function onJoinPool(bytes32 _poolId, address _sender, address _recipient, uint256[] _currentBalancesU112, uint256, uint256 _protocolFeeDU1F18, bytes _userData) external returns (uint256[] amountsInU112, uint256[] dueProtocolFeeAmountsU96)

Called by the Vault when a user calls IVault.joinPool. Can be use to add liquidity to the pool in exchange for Liquidity Provider (LP) pool tokens or to reward the pool with liquidity (MEV rewards from arbitrageurs). WARNING: The initial liquidity provider, in a call to join the pool with joinTypeU=0 (JoinType.Join), will sacrifice MINIMUM_LIQUIDITY, 1000, Liquidity Provider (LP) tokens. This may be an insignificant sacrifice for tokens with fewer decimal places and high worth (i.e. WBTC). Importantly, the reward capability remains when the pool is paused to mitigate any possible issue with underflowed pool reserves computed by differencing the pool accounting from the pool token balances.

Parameters

Return Values

onExitPool

function onExitPool(bytes32 _poolId, address _sender, address _recipient, uint256[] _currentBalancesU112, uint256, uint256 _protocolFeeDU1F18, bytes _userData) external returns (uint256[] amountsOutU112, uint256[] dueProtocolFeeAmountsU96)

Called by the Vault when a user calls IVault.exitPool. Can be used to remove liquidity from the pool in exchange for Liquidity Provider (LP) pool tokens, to withdraw proceeds of a Long-Term (LT) order, to cancel an LT order, or by the factory owner to withdraw protocol fees if they are being collected.

Parameters

Return Values

setAdminStatus

function setAdminStatus(address _admin, bool _status) external

Set the administrator status of the provided address, _admin. Status "true" gives administrative privileges, "false" removes privileges.

CAREFUL! You can remove all administrative privileges, rendering the contract unmanageable. NOTE: Must be called by the factory owner.

Parameters

setFeeAddress

function setFeeAddress(address _feeDestination) external

Enables Cron-Fi fee collection for Long-Term swaps when the provided address, _feeDestination is not the null address.

_CAREFUL! Only the feeDestination address can collect Cron-Fi fees from the pool. NOTE: Must be called by the factory owner.

Parameters

setPause

function setPause(bool _pauseValue) external

Sets whether the pool is paused or not. When the pool is paused: * New swaps of any kind cannot be issued. * Liquidity cannot be provided. * Virtual orders are not executed for the remainder of allowable operations, which include: removing liquidity, cancelling or withdrawing a Long-Term swap order, This is a safety measure that is not a part of expected pool operations.

NOTE: Must be called by an administrator.

Parameters

setParameter

function setParameter(uint256 _paramTypeU, uint256 _value) external

Set fee parameters.

NOTE: Total FP = 100,000. Thus a fee portion is the number of FP out of 100,000. NOTE: Must be called by an administrator.

Parameters

setCollectBalancerFees

function setCollectBalancerFees(bool _collectBalancerFee) external

Enable or disable the collection of Balancer Fees. When enabled Balancer takes a a portion of every fee collected in the pool. The pool remits fees to Balancer automatically when onJoinPool and onExitPool are called. Disabling balancer fees through this function supersedes any setting of balancer fee values in onJoinPool and onExitPool.

NOTE: Must be called by the factory owner.

Parameters

setFeeShift

function setFeeShift(uint256 _feeShift) external

Sets the fee shift that splits Long-Term (LT) swap fees remaining after Balancer's cut between the Liquidity Providers (LP) and Cron-Fi, if Cron-Fi fee collection is enabled.

NOTE: Must be called by the factory owner.

Parameters

setArbitragePartner

function setArbitragePartner(address _arbPartner, address _arbitrageList) external

Sets the arbitrageur list contract address, _arbitrageList, for an arbitrage partner, _arbPartner. To clear an arbitrage partner, set _arbitrageList to the null address.

NOTE: Must be called by an administrator.

Parameters

updateArbitrageList

function updateArbitrageList() external returns (address)

Advances the specified arbitrage partner (msg.sender) arbitrageur list contract to the newest contract, if available. See IArbitrageurList for details on the calls made by this contract to that interface's nextList function.

NOTE: Must be called by an arbitrage partner.

Return Values

executeVirtualOrdersToBlock

function executeVirtualOrdersToBlock(uint256 _maxBlock) external

Executes active virtual orders, Long-Term swaps, since the last virtual order block executed, updating reserve and other state variables to the current block.

Parameters

getVirtualPriceOracle

function getVirtualPriceOracle(uint256 _maxBlock) external returns (uint256 timestamp, uint256 token0U256F112, uint256 token1U256F112, uint256 blockNumber)

Get the virtual price oracle data for the pool at the specified block, _maxBlock.

    IMPORTANT - This function calls _getVirtualReserves, which triggers a re-entrancy check. Due
                to contract size challanges, there is no explicit call to that re-entrancy check
                in this function, where it's presence would be more obvious.

    IMPORTANT - This function does not meaningfully modify state despite the lack of a "view"
                designator for state mutability. (The call to _triggerVaultReentrancyCheck
                Unfortunately prevents the "view" designator as meaningless value is written
                to state to trigger a reentracy check).

    Runs virtual orders from the last virtual order block up to the current block to provide
    visibility into the current accounting for the pool.
    If the pool is paused, this function reflects the accounting values of the pool at
    the last virtual order block (i.e. it does not execute virtual orders to deliver the result).

_Check that blockNumber matches _maxBlock to ensure that maxBlock was correctly specified.

Parameters

Return Values

getVirtualReserves

function getVirtualReserves(uint256 _maxBlock, bool _paused) external returns (uint256 blockNumber, uint256 token0ReserveU112, uint256 token1ReserveU112, uint256 token0OrdersU112, uint256 token1OrdersU112, uint256 token0ProceedsU112, uint256 token1ProceedsU112, uint256 token0BalancerFeesU96, uint256 token1BalancerFeesU96, uint256 token0CronFiFeesU96, uint256 token1CronFiFeesU96)

Returns the TWAMM pool's reserves after the non-stateful execution of all virtual orders up to the specified maximum block (unless an invalid block is specified, which results in execution to the current block).

    IMPORTANT - This function calls _getVirtualReserves, which triggers a re-entrancy check. Due
                to contract size challanges, there is no explicit call to that re-entrancy check
                in this function, where it's presence would be more obvious.

    IMPORTANT - This function does not meaningfully modify state despite the lack of a "view"
                designator for state mutability. (The call to _triggerVaultReentrancyCheck
                Unfortunately prevents the "view" designator as meaningless value is written
                to state to trigger a reentracy check).

Parameters

Return Values

getPriceOracle

function getPriceOracle() external view returns (uint256 timestamp, uint256 token0U256F112, uint256 token1U256F112)

Get the price oracle data for the pool as of the last virtual order block.

Return Values

getOrderIds

function getOrderIds(address _owner, uint256 _offset, uint256 _maxResults) external view returns (uint256[] orderIds, uint256 numResults, uint256 totalResults)

Return an array of the order IDs for the specified user _owner. Allows all orders to be fetched at once or pagination through the _offset and _maxResults parameters. For instance to get the first 100 orderIds of a user, specify _offset=0 and _maxResults=100. To get the second 100 orderIds for the same user, specify _offset=100 and _maxResults=100. To get all results at once, either specify all known results or 0 for _maxResults.

Parameters

Return Values

getOrder

function getOrder(uint256 _orderId) external view returns (struct Order order)

Return the order information of a given order id.

Parameters

Return Values

getOrderIdCount

function getOrderIdCount() external view returns (uint256 nextOrderId)

Returns the number of virtual orders, Long-Term (LT) swaps, that have been transacted in this pool.

Return Values

getSalesRates

function getSalesRates() external view returns (uint256 salesRate0U112, uint256 salesRate1U112)

Returns the sales rate of each of the two order pools at the last virtual order block. This is the value persisted to state.

Return Values

getLastVirtualOrderBlock

function getLastVirtualOrderBlock() external view returns (uint256 lastVirtualOrderBlock)

Get the Last Virtual Order Block (LVOB) for the pool. This is the block number indicating the last block where virtual orders have been executed by the pool. If the LVOB is significantly less than the current block number, it indicates that the pool has been inactive and that a call to any function that requires the execution of virtual orders may incur siginificant gas use.

Return Values

getSalesRatesEndingPerBlock

function getSalesRatesEndingPerBlock(uint256 _blockNumber) external view returns (uint256 salesRateEndingPerBlock0U112, uint256 salesRateEndingPerBlock1U112)

Get the sales rate ending (per block) at the specified block number.

NOTE: these values are inserted into state at block numbers divisible by the Order Block Interval (OBI)--specifiying block numbers other than those evenly divisible by the OBI will result in the returned values being zero.

Parameters

getShortTermFeePoints

function getShortTermFeePoints() external view returns (uint256)

Gets the current Short-Term (ST) swap fee for the pool in Fee Points.

NOTE: Total FP = 100,000. Thus a fee portion is the number of FP out of 100,000.

Return Values

getPartnerFeePoints

function getPartnerFeePoints() external view returns (uint256)

Gets the current Partner swap fee for the pool in Fee Points.

NOTE: Total FP = 100,000. Thus a fee portion is the number of FP out of 100,000.

Return Values

getLongTermFeePoints

function getLongTermFeePoints() external view returns (uint256)

Gets the current Long-Term (LT) swap fee for the pool in Fee Points.

NOTE: Total FP = 100,000. Thus a fee portion is the number of FP out of 100,000.

Return Values

getOrderAmounts

function getOrderAmounts() external view returns (uint256 orders0U112, uint256 orders1U112)

Gets the amounts of Token0 and Token1 in active virtual orders waiting to be sold to the pool as of the last virtual order block.

Return Values

getProceedAmounts

function getProceedAmounts() external view returns (uint256 proceeds0U112, uint256 proceeds1U112)

Get the proceeds of Token0 and Token1 resulting from virtual orders, Long-Term swaps, up to the last virtual order block.

Return Values

getFeeShift

function getFeeShift() external view returns (uint256)

Gets the current value of the fee shift, which indicates how Long-Term (LT) swap fees are split between Cron-Fi and Liquidity Providers (LPs) when Cron-Fi fee collection is enabled.

Return Values

getCronFeeAmounts

function getCronFeeAmounts() external view returns (uint256 cronFee0U96, uint256 cronFee1U96)

Gets the amounts of Token0 and Token1 collected as Cron-Fi fees on Long-Term (LT) swaps as of the last virtual order block.

Return Values

isCollectingCronFees

function isCollectingCronFees() external view returns (bool)

Use to determine if the pool is collecting Cron-Fi fees currently (Cron-Fi fees are only collected on Long-Term swaps if enabled).

Return Values

isCollectingBalancerFees

function isCollectingBalancerFees() external view returns (bool)

Use to determine if the pool is collecting Balancer fees currently (Balancer fees apply to any fee collected by the pool--Short and Long Term swaps).

Return Values

getBalancerFee

function getBalancerFee() external view returns (uint256)

Get the Balancer Fee charged by the pool.

Return Values

getBalancerFeeAmounts

function getBalancerFeeAmounts() external view returns (uint256 balFee0U96, uint256 balFee1U96)

Gets the amounts of Token0 and Token1 collected as Balancer fees on all swaps as of the last virtual order block.

Return Values

isPaused

function isPaused() public view returns (bool)

Use to determine if the pool's virtual orders are currently paused. If virtual orders are paused, the pool will allow Long-Term (LT) swaps to be cancelled and withdrawn from as well as liquidity positions to be withdrawn.

Return Values

_senderIsFactoryOwner

function _senderIsFactoryOwner() internal view

Reverts with error if msg.sender is not the factory owner.

This internal function is a modifier contract size optimization.

_senderIsAdmin

function _senderIsAdmin() internal view

Reverts with error if msg.sender is not a pool administrator.

This internal function is a modifier contract size optimization.

_senderIsArbitragePartner

function _senderIsArbitragePartner() internal view

Reverts with error if msg.sender is not an arbitrage partner.

This internal function is a modifier contract size optimization.

_poolNotPaused

function _poolNotPaused() internal view

Reverts with error if the pool is paused.

This internal function is a modifier contract size optimization.

_calculateProceeds

function _calculateProceeds(uint256 _scaledProceedsU128, uint256 _startScaledProceedsU128, uint256 _salesRateU112, bool _token0To1) internal view returns (uint256 proceedsU112)

Computes the proceeds of a virtual order, Long-Term (LT) swap, for withdrawl or cancellation purposes. Proceeds are determined using the staking algorithm, where the user's order sales rate, _stakedAmountU128, represents their stake and the difference between the normalized proceeds at this juncture or their order end and order start are used to calculate their share. The normalized proceeds are stored in 128-bits with 64 fractional-bits, hence the scaling down by 64-bits below.

Note explanations for required underflow in this calculation below.

Parameters

Last updated