Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
TokenTracker
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x60995D90...2B83ab1c1 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
PoolNonTv
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.15; import "../Pool.sol";/* __ ___ _ _ \ \ / (_) | | | | \ \_/ / _ ___| | __| | \ / | |/ _ \ |/ _` | | | | | __/ | (_| | |_| |_|\___|_|\__,_| yieldprotocol.com ██████╗ ██████╗ ██████╗ ██╗ ███╗ ██╗ ██████╗ ███╗ ██╗████████╗██╗ ██╗ ██╔══██╗██╔═══██╗██╔═══██╗██║ ████╗ ██║██╔═══██╗████╗ ██║╚══██╔══╝██║ ██║ ██████╔╝██║ ██║██║ ██║██║ ██╔██╗ ██║██║ ██║██╔██╗ ██║ ██║ ██║ ██║ ██╔═══╝ ██║ ██║██║ ██║██║ ██║╚██╗██║██║ ██║██║╚██╗██║ ██║ ╚██╗ ██╔╝ ██║ ╚██████╔╝╚██████╔╝███████╗██║ ╚████║╚██████╔╝██║ ╚████║ ██║ ╚████╔╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═╝ ╚═══╝ .SOL */ /// Module for using non tokenized vault tokens as "shares" for the Yield Protocol Pool.sol AMM contract. /// For example ordinary DAI, as opposed to yvDAI or eDAI. /// @title PoolNonTv.sol /// @dev Deploy pool with base token and associated fyToken. /// @author @devtooligan contract PoolNonTv is Pool { using TransferHelper for IERC20Like; using Cast for uint256; constructor( address base_, address fyToken_, int128 ts_, uint16 g1Fee_ ) Pool(base_, fyToken_, ts_, g1Fee_) {} /* EXTERNAL FUNCTIONS *****************************************************************************************************************/ /// Retrieve any shares/base tokens not accounted for in the cache. /// Note: For PoolNonTv, sharesToken == baseToken. /// This fn is the same as retrieveBase(). /// @param to Address of the recipient of the shares/base tokens. /// @return retrieved The amount of shares/base tokens sent. function retrieveShares(address to) external virtual override returns (uint128 retrieved) { retrieved = _retrieveBase(to); } /// Retrieve any shares/base tokens not accounted for in the cache. /// Note: For PoolNonTv, sharesToken == baseToken. /// This fn is the same as retrieveShares(). /// @param to Address of the recipient of the shares/base tokens. /// @return retrieved The amount of shares/base tokens sent. function retrieveBase(address to) external virtual override returns (uint128 retrieved) { retrieved = _retrieveBase(to); } /* INTERNAL FUNCTIONS *****************************************************************************************************************/ /// Retrieve any shares/base tokens not accounted for in the cache. /// Note: For PoolNonTv, sharesToken == baseToken. /// This fn is used by both retrieveBase() and retrieveShares(). /// @param to Address of the recipient of the shares/base tokens. /// @return retrieved The amount of shares/base tokens sent. function _retrieveBase(address to) internal virtual returns (uint128 retrieved) { // For PoolNonTv, sharesToken == baseToken. This allows for the use of the core Pool.sol contract logic with // non-yield-bearing tokens. As such the sharesCached state var actually represents baseTokens, since they // are the same. retrieved = (sharesToken.balanceOf(address(this)) - sharesCached).u128(); sharesToken.safeTransfer(to, retrieved); } /// **This function is intentionally empty to overwrite the Pool._approveSharesToken fn.** /// This is normally used by Pool.constructor give max approval to sharesToken, but not needed for Non-Tv pool. function _approveSharesToken(IERC20Like baseToken_, address sharesToken_) internal virtual override {} /// This is used by the constructor to set the base token as immutable. /// For Non-tokenized vaults, the base is the same as the base asset. function _getBaseAsset(address sharesToken_) internal virtual override returns (IERC20Like) { return IERC20Like(sharesToken_); } /// Returns the current price of one share. For non-tokenized vaults this is always 1. /// This function should be overriden by modules. /// @return By always returning 1, we can use this module with any non-tokenized vault base such as WETH. function _getCurrentSharePrice() internal view virtual override returns (uint256) { return uint256(10**baseDecimals); } /// Internal function for wrapping base asset tokens. /// Since there is nothing to unwrap, we return the surplus balance. /// @return shares The amount of wrapped tokens that are sent to the receiver. function _wrap(address receiver) internal virtual override returns (uint256 shares) { shares = _getSharesBalance() - sharesCached; if (receiver != address(this)) { sharesToken.safeTransfer(receiver, shares); } } /// Internal function to preview how many shares will be received when depositing a given amount of assets. /// @param assets The amount of base asset tokens to preview the deposit. /// @return shares The amount of shares that would be returned from depositing. function _wrapPreview(uint256 assets) internal view virtual override returns (uint256 shares) { shares = assets; } /// Internal function for unwrapping unaccounted for base in this contract. /// Since there is nothing to unwrap, we return the surplus balance. /// @return assets The amount of base assets sent to the receiver. function _unwrap(address receiver) internal virtual override returns (uint256 assets) { assets = _getSharesBalance() - sharesCached; if (receiver != address(this)) { sharesToken.safeTransfer(receiver, assets); } } /// Internal function to preview how many asset tokens will be received when unwrapping a given amount of shares. /// @param shares The amount of shares to preview a redemption. /// @return assets The amount of base asset tokens that would be returned from redeeming. function _unwrapPreview(uint256 shares) internal view virtual override returns (uint256 assets) { assets = shares; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.15; import "./PoolImports.sol"; /* __ ___ _ _ \ \ / (_) | | | | ██████╗ ██████╗ ██████╗ ██╗ ███████╗ ██████╗ ██╗ \ \_/ / _ ___| | __| | ██╔══██╗██╔═══██╗██╔═══██╗██║ ██╔════╝██╔═══██╗██║ \ / | |/ _ \ |/ _` | ██████╔╝██║ ██║██║ ██║██║ ███████╗██║ ██║██║ | | | | __/ | (_| | ██╔═══╝ ██║ ██║██║ ██║██║ ╚════██║██║ ██║██║ |_| |_|\___|_|\__,_| ██║ ╚██████╔╝╚██████╔╝███████╗██╗███████║╚██████╔╝███████╗ yieldprotocol.com ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝╚══════╝ ╚═════╝ ╚══════╝ ┌─────────┐ │no │ │lifeguard│ └─┬─────┬─┘ ==+ be cool, stay in pool │ │ =======+ _____│_____│______ |+ \ .-'"___________________`-.|+ ( .'" '-.)+ |`-..__________________..-'|+ | |+ .-:::::::::::-. | |+ ┌──────────────┐ .:::::::::::::::::. | --- --- |+ │$ $│ : _______ __ __ : .| (o) (o) |+. │ ┌────────────┴─┐ :: | || | | |:: /`| |+'\ │ │$ $│ ::: | ___|| |_| |::: / /| [ |+\ \ │$│ ┌────────────┴─┐ ::: | |___ | |::: / / | ---------- |+ \ \ └─┤ │$ ERC4626 $│ ::: | ___||_ _|:::.-" ; \ \________/ /+ \ "--/│$│ Tokenized │ ::: | | | | ::),.-' `-..__________________..-' += `---=└─┤ Vault Shares │ :: |___| |___| ::=/ | | | | │$ $│ : TOKEN : | | | | └──────────────┘ `:::::::::::::::::' | | | | `-:::::::::::-' +----+ +----+ `'''''''` _..._|____| |____| _..._ .` "-. `% | | %` .-" `. / \ .: :. / \ '-..___|_..=:` `-:=.._|___..-' */ /// A Yieldspace AMM implementation for pools which provide liquidity and trading of fyTokens vs base tokens. /// **The base tokens in this implementation are converted to ERC4626 compliant tokenized vault shares.** /// See whitepaper and derived formulas: https://hackmd.io/lRZ4mgdrRgOpxZQXqKYlFw // // Useful terminology: // base - Example: DAI. The underlying token of the fyToken. Sometimes referred to as "asset" or "base". // shares - Example: yvDAI. Upon receipt, base is deposited (wrapped) in a tokenized vault. // c - Current price of shares in terms of base (in 64.64 bit) // mu - also called c0 is the initial c of shares at contract deployment // Reserves are tracked in shares * mu for consistency. // /// @title Pool.sol /// @dev Uses ABDK 64.64 mathlib for precision and reduced gas. /// @author Adapted by @devtooligan from original work by @alcueca and UniswapV2. Maths and whitepaper by @aniemerg. contract Pool is PoolEvents, IPool, ERC20Permit, AccessControl { /* LIBRARIES *****************************************************************************************************************/ using Math for uint256; using Math64x64 for int128; using Math64x64 for uint256; using Cast for uint128; using Cast for uint256; using TransferHelper for IMaturingToken; using TransferHelper for IERC20Like; /* MODIFIERS *****************************************************************************************************************/ /// Trading can only be done before maturity. modifier beforeMaturity() { if (block.timestamp >= maturity) revert AfterMaturity(); _; } /* IMMUTABLES *****************************************************************************************************************/ /// The fyToken for the corresponding base token. Ex. yvDAI's fyToken will be fyDAI. Even though we convert base /// in this contract to a wrapped tokenized vault (e.g. Yearn Vault Dai), the fyToken is still payable in /// the base token upon maturity. IMaturingToken public immutable fyToken; /// This pool accepts a pair of base and fyToken tokens. /// When these are deposited into a tokenized vault they become shares. /// It is an ERC20 token. IERC20Like public immutable baseToken; /// Decimals of base tokens (fyToken, lp token, and usually the sharesToken). uint256 public immutable baseDecimals; /// When base comes into this contract it is deposited into a 3rd party tokenized vault in return for shares. /// @dev For most of this contract, only the ERC20 functionality of the shares token is required. As such, shares /// are cast as "IERC20Like" and when that 4626 functionality is needed, they are recast as IERC4626. /// This wei, modules for non-4626 compliant base tokens can import this contract and override 4626 specific fn's. IERC20Like public immutable sharesToken; /// Time stretch == 1 / seconds in x years where x varies per contract (64.64) int128 public immutable ts; /// The normalization coefficient, the initial c value or price per 1 share of base (64.64) int128 public immutable mu; /// Pool's maturity date (not 64.64) uint32 public immutable maturity; /// Used to scale up to 18 decimals (not 64.64) uint96 public immutable scaleFactor; /* STRUCTS *****************************************************************************************************************/ struct Cache { uint16 g1Fee; uint104 sharesCached; uint104 fyTokenCached; uint32 blockTimestampLast; } /* STORAGE *****************************************************************************************************************/ // The following 4 vars use one storage slot and can be retrieved in a Cache struct with getCache() /// This number is used to calculate the fees for buying/selling fyTokens. /// @dev This is a fp4 that represents a ratio out 1, where 1 is represented by 10000. uint16 public g1Fee; /// Shares reserves, cached. uint104 internal sharesCached; /// fyToken reserves, cached. uint104 internal fyTokenCached; /// block.timestamp of last time reserve caches were updated. uint32 internal blockTimestampLast; /// This is a LAGGING, time weighted sum of the fyToken:shares reserves ratio measured in ratio seconds. /// @dev Footgun 🔫 alert! Be careful, this number is probably not what you need and it should normally be /// considered with blockTimestampLast. For consumption as a TWAR observation, use currentCumulativeRatio(). /// In future pools, this function's visibility may be changed to internal. /// @return a fixed point factor with 27 decimals (ray). uint256 public cumulativeRatioLast; /* CONSTRUCTOR FUNCTIONS *****************************************************************************************************************/ constructor( address sharesToken_, // address of shares token address fyToken_, // address of fyToken int128 ts_, // time stretch(64.64) uint16 g1Fee_ // fees (in bps) when buying fyToken ) ERC20Permit( string(abi.encodePacked(IERC20Like(fyToken_).name(), " LP")), string(abi.encodePacked(IERC20Like(fyToken_).symbol(), "LP")), IERC20Like(fyToken_).decimals() ) { /* __ __ __ ___ __ __ ___ __ __ / ` / \ |\ | /__` | |__) | | / ` | / \ |__) \__, \__/ | \| .__/ | | \ \__/ \__, | \__/ | \ */ // Set maturity with check to make sure its not 2107 yet. uint256 maturity_ = IMaturingToken(fyToken_).maturity(); if (maturity_ > uint256(type(uint32).max)) revert MaturityOverflow(); maturity = uint32(maturity_); // Set sharesToken. sharesToken = IERC20Like(sharesToken_); // Cache baseToken to save loads of SLOADs. IERC20Like baseToken_ = _getBaseAsset(sharesToken_); // Call approve hook for sharesToken. _approveSharesToken(baseToken_, sharesToken_); // NOTE: LP tokens, baseToken and fyToken should have the same decimals. Within this core contract, it is // presumed that sharesToken also has the same decimals. If this is not the case, a separate module must be // used to overwrite _getSharesBalance() and other affected functions (see PoolEuler.sol for example). baseDecimals = baseToken_.decimals(); // Set other immutables. baseToken = baseToken_; fyToken = IMaturingToken(fyToken_); ts = ts_; scaleFactor = uint96(10**(18 - uint96(baseDecimals))); // No more than 18 decimals allowed, reverts on underflow. // Set mu with check for 0. if ((mu = _getC()) == 0) { revert MuCannotBeZero(); } // Set g1Fee state variable with out of bounds check. if ((g1Fee = g1Fee_) > 10000) revert InvalidFee(g1Fee_); emit FeesSet(g1Fee_); } /// This is used by the constructor to give max approval to sharesToken. /// @dev This should be overridden by modules if needed. /// @dev safeAprove will revert approve is unsuccessful function _approveSharesToken(IERC20Like baseToken_, address sharesToken_) internal virtual { baseToken_.safeApprove(sharesToken_, type(uint256).max); } /// This is used by the constructor to set the base token as immutable. /// @dev This should be overridden by modules. /// We use the IERC20Like interface, but this should be an ERC20 asset per EIP4626. function _getBaseAsset(address sharesToken_) internal virtual returns (IERC20Like) { return IERC20Like(address(IERC4626(sharesToken_).asset())); } /* LIQUIDITY FUNCTIONS ┌─────────────────────────────────────────────────┐ │ mint, new life. gm! │ │ buy, sell, mint more, trade, trade -- stop │ │ mature, burn. gg~ │ │ │ │ "Watashinojinsei (My Life)" - haiku by Poolie │ └─────────────────────────────────────────────────┘ *****************************************************************************************************************/ /*mint v ___ \ / |_ \_/ ┌───────────────────────────────┐ | | │ │ ` _......._ ' gm! \│ │/ .-:::::::::::-. │ \│ │/ ` : __ ____ : / └───────────────► │ mint │ :: / / / __ \:: │ │ ──────▶ _ :: / / / /_/ /:: _ ┌───────────────► │ │ :: / /___/ ____/ :: │ /│ │\ ::/_____/_/ :: /│ │\ ' : : ` B A S E │ \(^o^)/ │ `-:::::::::::-' │ Pool.sol │ , `'''''''` . └───────────────────────────────┘ / \ ^ */ /// Mint liquidity tokens in exchange for adding base and fyToken /// The amount of liquidity tokens to mint is calculated from the amount of unaccounted for fyToken in this contract. /// A proportional amount of asset tokens need to be present in this contract, also unaccounted for. /// @dev _totalSupply > 0 check important here to prevent unauthorized initialization. /// @param to Wallet receiving the minted liquidity tokens. /// @param remainder Wallet receiving any surplus base. /// @param minRatio Minimum ratio of shares to fyToken in the pool (fp18). /// @param maxRatio Maximum ratio of shares to fyToken in the pool (fp18). /// @return baseIn The amount of base found in the contract that was used for the mint. /// @return fyTokenIn The amount of fyToken found that was used for the mint /// @return lpTokensMinted The amount of LP tokens minted. function mint( address to, address remainder, uint256 minRatio, uint256 maxRatio ) external virtual override returns ( uint256 baseIn, uint256 fyTokenIn, uint256 lpTokensMinted ) { if (_totalSupply == 0) revert NotInitialized(); (baseIn, fyTokenIn, lpTokensMinted) = _mint(to, remainder, 0, minRatio, maxRatio); } // ╦┌┐┌┬┌┬┐┬┌─┐┬ ┬┌─┐┌─┐ ╔═╗┌─┐┌─┐┬ // ║││││ │ │├─┤│ │┌─┘├┤ ╠═╝│ ││ ││ // ╩┘└┘┴ ┴ ┴┴ ┴┴─┘┴└─┘└─┘ ╩ └─┘└─┘┴─┘ /// @dev This is the exact same as mint() but with auth added and skip the supply > 0 check /// and checks instead that supply == 0. /// This intialize mechanism is different than UniV2. Tokens addresses are added at contract creation. /// This pool is considered initialized after the first LP token is minted. /// @param to Wallet receiving the minted liquidity tokens. /// @return baseIn The amount of base found that was used for the mint. /// @return fyTokenIn The amount of fyToken found that was used for the mint /// @return lpTokensMinted The amount of LP tokens minted. function init(address to) external virtual auth returns ( uint256 baseIn, uint256 fyTokenIn, uint256 lpTokensMinted ) { if (_totalSupply != 0) revert Initialized(); // address(this) used for the remainder, but actually this parameter is not used at all in this case because // there will never be any left over base in this case (baseIn, fyTokenIn, lpTokensMinted) = _mint(to, address(this), 0, 0, type(uint256).max); emit gm(); } /* mintWithBase V ┌───────────────────────────────┐ \ / │ │ ` _......._ ' gm! \│ │/ .-:::::::::::-. \│ │/ ` : __ ____ : / │ mintWithBase │ :: / / / __ \:: B A S E ──────► │ │ ──────▶ _ :: / / / /_/ /:: _ │ │ :: / /___/ ____/ :: /│ │\ ::/_____/_/ :: /│ │\ ' : : ` │ \(^o^)/ │ `-:::::::::::-' │ Pool.sol │ , `'''''''` . └───────────────────────────────┘ / \ ^ */ /// Mint liquidity tokens in exchange for adding only base. /// The amount of liquidity tokens is calculated from the amount of fyToken to buy from the pool. /// The base tokens need to be previously transferred and present in this contract. /// @dev _totalSupply > 0 check important here to prevent minting before initialization. /// @param to Wallet receiving the minted liquidity tokens. /// @param remainder Wallet receiving any leftover base at the end. /// @param fyTokenToBuy Amount of `fyToken` being bought in the Pool, from this we calculate how much base it will be taken in. /// @param minRatio Minimum ratio of shares to fyToken in the pool (fp18). /// @param maxRatio Maximum ratio of shares to fyToken in the pool (fp18). /// @return baseIn The amount of base found that was used for the mint. /// @return fyTokenIn The amount of fyToken found that was used for the mint /// @return lpTokensMinted The amount of LP tokens minted. function mintWithBase( address to, address remainder, uint256 fyTokenToBuy, uint256 minRatio, uint256 maxRatio ) external virtual override returns ( uint256 baseIn, uint256 fyTokenIn, uint256 lpTokensMinted ) { if (_totalSupply == 0) revert NotInitialized(); (baseIn, fyTokenIn, lpTokensMinted) = _mint(to, remainder, fyTokenToBuy, minRatio, maxRatio); } /// This is the internal function called by the external mint functions. /// Mint liquidity tokens, with an optional internal trade to buy fyToken beforehand. /// The amount of liquidity tokens is calculated from the amount of fyTokenToBuy from the pool, /// plus the amount of extra, unaccounted for fyToken in this contract. /// The base tokens also need to be previously transferred and present in this contract. /// Only usable before maturity. /// @dev Warning: This fn does not check if supply > 0 like the external functions do. /// This function overloads the ERC20._mint(address, uint) function. /// @param to Wallet receiving the minted liquidity tokens. /// @param remainder Wallet receiving any surplus base. /// @param fyTokenToBuy Amount of `fyToken` being bought in the Pool. /// @param minRatio Minimum ratio of shares to fyToken in the pool (fp18). /// @param maxRatio Maximum ratio of shares to fyToken in the pool (fp18). /// @return baseIn The amount of base found that was used for the mint. /// @return fyTokenIn The amount of fyToken found that was used for the mint /// @return lpTokensMinted The amount of LP tokens minted. function _mint( address to, address remainder, uint256 fyTokenToBuy, uint256 minRatio, uint256 maxRatio ) internal beforeMaturity returns ( uint256 baseIn, uint256 fyTokenIn, uint256 lpTokensMinted ) { // Wrap all base found in this contract. baseIn = baseToken.balanceOf(address(this)); _wrap(address(this)); // Gather data uint256 supply = _totalSupply; Cache memory cache = _getCache(); uint256 realFYTokenCached_ = cache.fyTokenCached - supply; // The fyToken cache includes the virtual fyToken, equal to the supply uint256 sharesBalance = _getSharesBalance(); // Check the burn wasn't sandwiched if (realFYTokenCached_ != 0) { if ( uint256(cache.sharesCached).wdiv(realFYTokenCached_) < minRatio || uint256(cache.sharesCached).wdiv(realFYTokenCached_) > maxRatio ) revert SlippageDuringMint(uint256(cache.sharesCached).wdiv(realFYTokenCached_), minRatio, maxRatio); } else if (maxRatio < type(uint256).max) { revert SlippageDuringMint(type(uint256).max, minRatio, maxRatio); } // Calculate token amounts uint256 sharesIn; if (supply == 0) { // **First mint** // Initialize at 1 pool token sharesIn = sharesBalance; lpTokensMinted = _mulMu(sharesIn); } else if (realFYTokenCached_ == 0) { // Edge case, no fyToken in the Pool after initialization sharesIn = sharesBalance - cache.sharesCached; lpTokensMinted = (supply * sharesIn) / cache.sharesCached; } else { // There is an optional virtual trade before the mint uint256 sharesToSell; if (fyTokenToBuy != 0) { sharesToSell = _buyFYTokenPreview( fyTokenToBuy.u128(), cache.sharesCached, cache.fyTokenCached, _computeG1(cache.g1Fee) ); } // We use all the available fyTokens, plus optional virtual trade. Surplus is in base tokens. fyTokenIn = fyToken.balanceOf(address(this)) - realFYTokenCached_; lpTokensMinted = (supply * (fyTokenToBuy + fyTokenIn)) / (realFYTokenCached_ - fyTokenToBuy); sharesIn = sharesToSell + ((cache.sharesCached + sharesToSell) * lpTokensMinted) / supply; if ((sharesBalance - cache.sharesCached) < sharesIn) { revert NotEnoughBaseIn(_unwrapPreview(sharesBalance - cache.sharesCached), _unwrapPreview(sharesIn)); } } // Update TWAR _update( (cache.sharesCached + sharesIn).u128(), (cache.fyTokenCached + fyTokenIn + lpTokensMinted).u128(), // Include "virtual" fyToken from new minted LP tokens cache.sharesCached, cache.fyTokenCached ); // Execute mint _mint(to, lpTokensMinted); // Return any unused base tokens if (sharesBalance > cache.sharesCached + sharesIn) _unwrap(remainder); // confirm new virtual fyToken balance is not less than new supply if ((cache.fyTokenCached + fyTokenIn + lpTokensMinted) < supply + lpTokensMinted) { revert FYTokenCachedBadState(); } emit Liquidity( maturity, msg.sender, to, address(0), -(baseIn.i256()), -(fyTokenIn.i256()), lpTokensMinted.i256() ); } /* burn ( ( ) ( ( (| (| ) ) )\/ ( \/(( ( gg ___ (( / ))\))))\ ┌~~~~~~► |_ \_/ )\( | ) │ | | /: | __ ____/: │ :: / / / __ \:: ───┤ :: / / / /_/ /:: │ :: / /___/ ____/ :: └~~~~~~► B A S E ::/_____/_/ :: : : `-:::::::::::-' `'''''''` */ /// Burn liquidity tokens in exchange for base and fyToken. /// The liquidity tokens need to be previously tranfsferred to this contract. /// @param baseTo Wallet receiving the base tokens. /// @param fyTokenTo Wallet receiving the fyTokens. /// @param minRatio Minimum ratio of shares to fyToken in the pool (fp18). /// @param maxRatio Maximum ratio of shares to fyToken in the pool (fp18). /// @return lpTokensBurned The amount of LP tokens burned. /// @return baseOut The amount of base tokens received. /// @return fyTokenOut The amount of fyTokens received. function burn( address baseTo, address fyTokenTo, uint256 minRatio, uint256 maxRatio ) external virtual override returns ( uint256 lpTokensBurned, uint256 baseOut, uint256 fyTokenOut ) { (lpTokensBurned, baseOut, fyTokenOut) = _burn(baseTo, fyTokenTo, false, minRatio, maxRatio); } /* burnForBase ( ( ) ( ( (| (| ) ) )\/ ( \/(( ( gg (( / ))\))))\ )\( | ) /: | __ ____/: :: / / / __ \:: ~~~~~~~► B A S E :: / / / /_/ /:: :: / /___/ ____/ :: ::/_____/_/ :: : : `-:::::::::::-' `'''''''` */ /// Burn liquidity tokens in exchange for base. /// The liquidity provider needs to have called `pool.approve`. /// Only usable before maturity. /// @param to Wallet receiving the base and fyToken. /// @param minRatio Minimum ratio of shares to fyToken in the pool (fp18). /// @param maxRatio Maximum ratio of shares to fyToken in the pool (fp18). /// @return lpTokensBurned The amount of lp tokens burned. /// @return baseOut The amount of base tokens returned. function burnForBase( address to, uint256 minRatio, uint256 maxRatio ) external virtual override beforeMaturity returns (uint256 lpTokensBurned, uint256 baseOut) { (lpTokensBurned, baseOut, ) = _burn(to, address(0), true, minRatio, maxRatio); } /// Burn liquidity tokens in exchange for base. /// The liquidity provider needs to have called `pool.approve`. /// @dev This function overloads the ERC20._burn(address, uint) function. /// @param baseTo Wallet receiving the base. /// @param fyTokenTo Wallet receiving the fyToken. /// @param tradeToBase Whether the resulting fyToken should be traded for base tokens. /// @param minRatio Minimum ratio of shares to fyToken in the pool (fp18). /// @param maxRatio Maximum ratio of shares to fyToken in the pool (fp18). /// @return lpTokensBurned The amount of pool tokens burned. /// @return baseOut The amount of base tokens returned. /// @return fyTokenOut The amount of fyTokens returned. function _burn( address baseTo, address fyTokenTo, bool tradeToBase, uint256 minRatio, uint256 maxRatio ) internal returns ( uint256 lpTokensBurned, uint256 baseOut, uint256 fyTokenOut ) { // Gather data lpTokensBurned = _balanceOf[address(this)]; uint256 supply = _totalSupply; Cache memory cache = _getCache(); uint96 scaleFactor_ = scaleFactor; // The fyToken cache includes the virtual fyToken, equal to the supply. uint256 realFYTokenCached_ = cache.fyTokenCached - supply; // Check the burn wasn't sandwiched if (realFYTokenCached_ != 0) { if ( (uint256(cache.sharesCached).wdiv(realFYTokenCached_) < minRatio) || (uint256(cache.sharesCached).wdiv(realFYTokenCached_) > maxRatio) ) { revert SlippageDuringBurn(uint256(cache.sharesCached).wdiv(realFYTokenCached_), minRatio, maxRatio); } } // Calculate trade uint256 sharesOut = (lpTokensBurned * cache.sharesCached) / supply; fyTokenOut = (lpTokensBurned * realFYTokenCached_) / supply; if (tradeToBase) { sharesOut += YieldMath.sharesOutForFYTokenIn( // This is a virtual sell (cache.sharesCached - sharesOut.u128()) * scaleFactor_, // Cache, minus virtual burn (cache.fyTokenCached - fyTokenOut.u128()) * scaleFactor_, // Cache, minus virtual burn fyTokenOut.u128() * scaleFactor_, // Sell the virtual fyToken obtained maturity - uint32(block.timestamp), // This can't be called after maturity ts, _computeG2(cache.g1Fee), _getC(), mu ) / scaleFactor_; fyTokenOut = 0; } // Update TWAR _update( (cache.sharesCached - sharesOut).u128(), (cache.fyTokenCached - fyTokenOut - lpTokensBurned).u128(), // Exclude "virtual" fyToken from new minted LP tokens cache.sharesCached, cache.fyTokenCached ); // Burn and transfer _burn(address(this), lpTokensBurned); // This is calling the actual ERC20 _burn. baseOut = _unwrap(baseTo); if (fyTokenOut != 0) fyToken.safeTransfer(fyTokenTo, fyTokenOut); // confirm new virtual fyToken balance is not less than new supply if ((cache.fyTokenCached - fyTokenOut - lpTokensBurned) < supply - lpTokensBurned) { revert FYTokenCachedBadState(); } emit Liquidity( maturity, msg.sender, baseTo, fyTokenTo, baseOut.i256(), fyTokenOut.i256(), -(lpTokensBurned.i256()) ); if (supply == lpTokensBurned && block.timestamp >= maturity) { emit gg(); } } /* TRADING FUNCTIONS ****************************************************************************************************************/ /* buyBase I want to buy `uint128 baseOut` worth of base tokens. _______ I've transferred you some fyTokens -- that should be enough. / GUY \ .:::::::::::::::::. (^^^| \=========== : _______ __ __ : ┌─────────┐ \(\/ | _ _ | :: | || | | |:: │no │ \ \ (. o o | ::: | ___|| |_| |::: │lifeguard│ \ \ | ~ | ::: | |___ | |::: └─┬─────┬─┘ ==+ \ \ \ == / ::: | ___||_ _|:: ok guy │ │ =======+ \ \___| |___ ::: | | | | ::: _____│_____│______ |+ \ / \__/ \ :: |___| |___| :: .-'"___________________`-.|+ \ \ : : ( .'" '-.)+ --| GUY |\_/\ / `:::::::::::::::::' |`-..__________________..-'|+ | | \ \/ / `-:::::::::::-' | |+ | | \ / `'''''''` | |+ | | \_/ | --- --- |+ |______| | (o ) (o ) |+ |__GG__| ┌──────────────┐ /`| |+ | | │$ $│ / /| [ |+ | | | │ B A S E │ / / | ---------- |+ | | _| │ baseOut │\.-" ; \ \________/ /+ | | | │$ $│),.-' `-..__________________..-' += | | | └──────────────┘ | | | | ( ( | | | | | | | | | | | | | | | T----T T----T _| | | _..._L____J L____J _..._ (_____[__) .` "-. `% | | %` .-" `. / \ .: :. / \ '-..___|_..=:` `-:=.._|___..-' */ /// Buy base with fyToken. /// The trader needs to have transferred in the necessary amount of fyTokens in advance. /// @param to Wallet receiving the base being bought. /// @param baseOut Amount of base being bought that will be deposited in `to` wallet. /// @param max This has been deprecated and was left in for backwards compatibility. /// @return fyTokenIn Amount of fyToken that will be taken from caller. function buyBase( address to, uint128 baseOut, uint128 max ) external virtual override returns (uint128 fyTokenIn) { // Calculate trade and cache values uint128 fyTokenBalance = _getFYTokenBalance(); Cache memory cache = _getCache(); uint128 sharesOut = _wrapPreview(baseOut).u128(); fyTokenIn = _buyBasePreview(sharesOut, cache.sharesCached, cache.fyTokenCached, _computeG2(cache.g1Fee)); // Checks if (fyTokenBalance - cache.fyTokenCached < fyTokenIn) { revert NotEnoughFYTokenIn(fyTokenBalance - cache.fyTokenCached, fyTokenIn); } // Update TWAR _update( cache.sharesCached - sharesOut, cache.fyTokenCached + fyTokenIn, cache.sharesCached, cache.fyTokenCached ); // Transfer _unwrap(to); emit Trade(maturity, msg.sender, to, baseOut.i128(), -(fyTokenIn.i128())); } /// Returns how much fyToken would be required to buy `baseOut` base. /// @dev Note: This fn takes baseOut as a param while the internal fn takes sharesOut. /// @param baseOut Amount of base hypothetically desired. /// @return fyTokenIn Amount of fyToken hypothetically required. function buyBasePreview(uint128 baseOut) external view virtual override returns (uint128 fyTokenIn) { Cache memory cache = _getCache(); fyTokenIn = _buyBasePreview( _wrapPreview(baseOut).u128(), cache.sharesCached, cache.fyTokenCached, _computeG2(cache.g1Fee) ); } /// Returns how much fyToken would be required to buy `sharesOut`. /// @dev Note: This fn takes sharesOut as a param while the external fn takes baseOut. function _buyBasePreview( uint128 sharesOut, uint104 sharesBalance, uint104 fyTokenBalance, int128 g2_ ) internal view beforeMaturity returns (uint128 fyTokenIn) { uint96 scaleFactor_ = scaleFactor; fyTokenIn = YieldMath.fyTokenInForSharesOut( sharesBalance * scaleFactor_, fyTokenBalance * scaleFactor_, sharesOut * scaleFactor_, maturity - uint32(block.timestamp), // This can't be called after maturity ts, g2_, _getC(), mu ) / scaleFactor_; } /*buyFYToken I want to buy `uint128 fyTokenOut` worth of fyTokens. _______ I've transferred you some base tokens -- that should be enough. / GUY \ ┌─────────┐ (^^^| \=========== ┌──────────────┐ │no │ \(\/ | _ _ | │$ $│ │lifeguard│ \ \ (. o o | │ ┌────────────┴─┐ └─┬─────┬─┘ ==+ \ \ | ~ | │ │$ $│ hmm, let's see here │ │ =======+ \ \ \ == / │ │ B A S E │ _____│_____│______ |+ \ \___| |___ │$│ │ .-'"___________________`-.|+ \ / \__/ \ └─┤$ $│ ( .'" '-.)+ \ \ └──────────────┘ |`-..__________________..-'|+ --| GUY |\_/\ / / | |+ | | \ \/ / | |+ | | \ / _......._ /`| --- --- |+ | | \_/ .-:::::::::::-. / /| (o ) (o ) |+ |______| .:::::::::::::::::. / / | |+ |__GG__| : _______ __ __ : _.-" ; | [ |+ | | :: | || | | |::),.-' | ---------- |+ | | | ::: | ___|| |_| |:::/ \ \________/ /+ | | _| ::: | |___ | |::: `-..__________________..-' += | | | ::: | ___||_ _|::: | | | | | | | ::: | | | | ::: | | | | ( ( | :: |___| |___| :: | | | | | | | : fyTokenOut : T----T T----T | | | `:::::::::::::::::' _..._L____J L____J _..._ _| | | `-:::::::::::-' .` "-. `% | | %` .-" `. (_____[__) `'''''''` / \ .: :. / \ '-..___|_..=:` `-:=.._|___..-' */ /// Buy fyToken with base. /// The trader needs to have transferred in the correct amount of base tokens in advance. /// @param to Wallet receiving the fyToken being bought. /// @param fyTokenOut Amount of fyToken being bought that will be deposited in `to` wallet. /// @param max This has been deprecated and was left in for backwards compatibility. /// @return baseIn Amount of base that will be used. function buyFYToken( address to, uint128 fyTokenOut, uint128 max ) external virtual override returns (uint128 baseIn) { // Wrap any base assets found in contract. _wrap(address(this)); // Calculate trade uint128 sharesBalance = _getSharesBalance(); Cache memory cache = _getCache(); uint128 sharesIn = _buyFYTokenPreview( fyTokenOut, cache.sharesCached, cache.fyTokenCached, _computeG1(cache.g1Fee) ); baseIn = _unwrapPreview(sharesIn).u128(); // Checks if (sharesBalance - cache.sharesCached < sharesIn) revert NotEnoughBaseIn(_unwrapPreview(sharesBalance - cache.sharesCached), baseIn); // Update TWAR _update( cache.sharesCached + sharesIn, cache.fyTokenCached - fyTokenOut, cache.sharesCached, cache.fyTokenCached ); // Transfer fyToken.safeTransfer(to, fyTokenOut); // confirm new virtual fyToken balance is not less than new supply if ((cache.fyTokenCached - fyTokenOut) < _totalSupply) { revert FYTokenCachedBadState(); } emit Trade(maturity, msg.sender, to, -(baseIn.i128()), fyTokenOut.i128()); } /// Returns how much base would be required to buy `fyTokenOut`. /// @param fyTokenOut Amount of fyToken hypothetically desired. /// @dev Note: This returns an amount in base. The internal fn returns amount of shares. /// @return baseIn Amount of base hypothetically required. function buyFYTokenPreview(uint128 fyTokenOut) external view virtual override returns (uint128 baseIn) { Cache memory cache = _getCache(); uint128 sharesIn = _buyFYTokenPreview( fyTokenOut, cache.sharesCached, cache.fyTokenCached, _computeG1(cache.g1Fee) ); baseIn = _unwrapPreview(sharesIn).u128(); } /// Returns how many shares are required to buy `fyTokenOut` fyTokens. /// @dev Note: This returns an amount in shares. The external fn returns amount of base. function _buyFYTokenPreview( uint128 fyTokenOut, uint128 sharesBalance, uint128 fyTokenBalance, int128 g1_ ) internal view beforeMaturity returns (uint128 sharesIn) { uint96 scaleFactor_ = scaleFactor; sharesIn = YieldMath.sharesInForFYTokenOut( sharesBalance * scaleFactor_, fyTokenBalance * scaleFactor_, fyTokenOut * scaleFactor_, maturity - uint32(block.timestamp), // This can't be called after maturity ts, g1_, _getC(), mu ) / scaleFactor_; uint128 newSharesMulMu = _mulMu(sharesBalance + sharesIn).u128(); if ((fyTokenBalance - fyTokenOut) < newSharesMulMu) { revert NegativeInterestRatesNotAllowed(fyTokenBalance - fyTokenOut, newSharesMulMu); } } /* sellBase I've transfered you some base tokens. _______ Can you swap them for fyTokens? / GUY \ ┌─────────┐ (^^^| \=========== ┌──────────────┐ │no │ \(\/ | _ _ | │$ $│ │lifeguard│ \ \ (. o o | │ ┌────────────┴─┐ └─┬─────┬─┘ ==+ \ \ | ~ | │ │$ $│ can │ │ =======+ \ \ \ == / │ │ │ _____│_____│______ |+ \ \___| |___ │$│ baseIn │ .-'"___________________`-.|+ \ / \__/ \ └─┤$ $│ ( .'" '-.)+ \ \ ( └──────────────┘ |`-..__________________..-'|+ --| GUY |\_/\ / / | |+ | | \ \/ / | |+ | | \ / _......._ /`| --- --- |+ | | \_/ .-:::::::::::-. / /| (o ) (o ) |+ |______| .:::::::::::::::::. / / | |+ |__GG__| : _______ __ __ : _.-" ; | [ |+ | | :: | || | | |::),.-' | ---------- |+ | | | ::: | ___|| |_| |:::/ \ \________/ /+ | | _| ::: | |___ | |::: `-..__________________..-' += | | | ::: | ___||_ _|::: | | | | | | | ::: | | | | ::: | | | | ( ( | :: |___| |___| :: | | | | | | | : ???? : T----T T----T | | | `:::::::::::::::::' _..._L____J L____J _..._ _| | | `-:::::::::::-' .` "-. `% | | %` .-" `. (_____[__) `'''''''` / \ .: :. / \ '-..___|_..=:` `-:=.._|___..-' */ /// Sell base for fyToken. /// The trader needs to have transferred the amount of base to sell to the pool before calling this fn. /// @param to Wallet receiving the fyToken being bought. /// @param min Minimum accepted amount of fyToken. /// @return fyTokenOut Amount of fyToken that will be deposited on `to` wallet. function sellBase(address to, uint128 min) external virtual override returns (uint128 fyTokenOut) { // Wrap any base assets found in contract. _wrap(address(this)); // Calculate trade Cache memory cache = _getCache(); uint104 sharesBalance = _getSharesBalance(); uint128 sharesIn = sharesBalance - cache.sharesCached; fyTokenOut = _sellBasePreview(sharesIn, cache.sharesCached, cache.fyTokenCached, _computeG1(cache.g1Fee)); // Check slippage if (fyTokenOut < min) revert SlippageDuringSellBase(fyTokenOut, min); // Update TWAR _update(sharesBalance, cache.fyTokenCached - fyTokenOut, cache.sharesCached, cache.fyTokenCached); // Transfer fyToken.safeTransfer(to, fyTokenOut); // confirm new virtual fyToken balance is not less than new supply if ((cache.fyTokenCached - fyTokenOut) < _totalSupply) { revert FYTokenCachedBadState(); } emit Trade(maturity, msg.sender, to, -(_unwrapPreview(sharesIn).u128().i128()), fyTokenOut.i128()); } /// Returns how much fyToken would be obtained by selling `baseIn`. /// @dev Note: This external fn takes baseIn while the internal fn takes sharesIn. /// @param baseIn Amount of base hypothetically sold. /// @return fyTokenOut Amount of fyToken hypothetically bought. function sellBasePreview(uint128 baseIn) external view virtual override returns (uint128 fyTokenOut) { Cache memory cache = _getCache(); fyTokenOut = _sellBasePreview( _wrapPreview(baseIn).u128(), cache.sharesCached, cache.fyTokenCached, _computeG1(cache.g1Fee) ); } /// Returns how much fyToken would be obtained by selling `sharesIn`. /// @dev Note: This internal fn takes sharesIn while the external fn takes baseIn. function _sellBasePreview( uint128 sharesIn, uint104 sharesBalance, uint104 fyTokenBalance, int128 g1_ ) internal view beforeMaturity returns (uint128 fyTokenOut) { uint96 scaleFactor_ = scaleFactor; fyTokenOut = YieldMath.fyTokenOutForSharesIn( sharesBalance * scaleFactor_, fyTokenBalance * scaleFactor_, sharesIn * scaleFactor_, maturity - uint32(block.timestamp), // This can't be called after maturity ts, g1_, _getC(), mu ) / scaleFactor_; uint128 newSharesMulMu = _mulMu(sharesBalance + sharesIn).u128(); if ((fyTokenBalance - fyTokenOut) < newSharesMulMu) { revert NegativeInterestRatesNotAllowed(fyTokenBalance - fyTokenOut, newSharesMulMu); } } /*sellFYToken I've transferred you some fyTokens. _______ Can you swap them for base? / GUY \ .:::::::::::::::::. (^^^| \=========== : _______ __ __ : ┌─────────┐ \(\/ | _ _ | :: | || | | |:: │no │ \ \ (. o o | ::: | ___|| |_| |::: │lifeguard│ \ \ | ~ | ::: | |___ | |::: └─┬─────┬─┘ ==+ \ \ \ == / ::: | ___||_ _|::: lfg │ │ =======+ \ \___| |___ ::: | | | | ::: _____│_____│______ |+ \ / \__/ \ :: |___| |___| :: .-'"___________________`-.|+ \ \ : fyTokenIn : ( .'" '-.)+ --| GUY |\_/\ / `:::::::::::::::::' |`-..__________________..-'|+ | | \ \/ / `-:::::::::::-' | |+ | | \ / `'''''''` | |+ | | \_/ | --- --- |+ |______| | (o ) (o ) |+ |__GG__| ┌──────────────┐ /`| |+ | | │$ $│ / /| [ |+ | | | │ B A S E │ / / | ---------- |+ | | _| │ ???? │\.-" ; \ \________/ /+ | | | │$ $│),.-' `-..__________________..-' += | | | └──────────────┘ | | | | ( ( | | | | | | | | | | | | | | | T----T T----T _| | | _..._L____J L____J _..._ (_____[__) .` "-. `% | | %` .-" `. / \ .: :. / \ '-..___|_..=:` `-:=.._|___..-' */ /// Sell fyToken for base. /// The trader needs to have transferred the amount of fyToken to sell to the pool before in the same transaction. /// @param to Wallet receiving the base being bought. /// @param min Minimum accepted amount of base. /// @return baseOut Amount of base that will be deposited on `to` wallet. function sellFYToken(address to, uint128 min) external virtual override returns (uint128 baseOut) { // Calculate trade Cache memory cache = _getCache(); uint104 fyTokenBalance = _getFYTokenBalance(); uint128 fyTokenIn = fyTokenBalance - cache.fyTokenCached; uint128 sharesOut = _sellFYTokenPreview( fyTokenIn, cache.sharesCached, cache.fyTokenCached, _computeG2(cache.g1Fee) ); // Update TWAR _update(cache.sharesCached - sharesOut, fyTokenBalance, cache.sharesCached, cache.fyTokenCached); // Transfer baseOut = _unwrap(to).u128(); // Check slippage if (baseOut < min) revert SlippageDuringSellFYToken(baseOut, min); emit Trade(maturity, msg.sender, to, baseOut.i128(), -(fyTokenIn.i128())); } /// Returns how much base would be obtained by selling `fyTokenIn` fyToken. /// @dev Note: This external fn returns baseOut while the internal fn returns sharesOut. /// @param fyTokenIn Amount of fyToken hypothetically sold. /// @return baseOut Amount of base hypothetically bought. function sellFYTokenPreview(uint128 fyTokenIn) public view virtual returns (uint128 baseOut) { Cache memory cache = _getCache(); uint128 sharesOut = _sellFYTokenPreview( fyTokenIn, cache.sharesCached, cache.fyTokenCached, _computeG2(cache.g1Fee) ); baseOut = _unwrapPreview(sharesOut).u128(); } /// Returns how much shares would be obtained by selling `fyTokenIn` fyToken. /// @dev Note: This internal fn returns sharesOut while the external fn returns baseOut. function _sellFYTokenPreview( uint128 fyTokenIn, uint104 sharesBalance, uint104 fyTokenBalance, int128 g2_ ) internal view beforeMaturity returns (uint128 sharesOut) { uint96 scaleFactor_ = scaleFactor; sharesOut = YieldMath.sharesOutForFYTokenIn( sharesBalance * scaleFactor_, fyTokenBalance * scaleFactor_, fyTokenIn * scaleFactor_, maturity - uint32(block.timestamp), // This can't be called after maturity ts, g2_, _getC(), mu ) / scaleFactor_; } /* LIQUIDITY FUNCTIONS ****************************************************************************************************************/ /// @inheritdoc IPool function maxFYTokenIn() public view override returns (uint128 fyTokenIn) { uint96 scaleFactor_ = scaleFactor; Cache memory cache = _getCache(); fyTokenIn = YieldMath.maxFYTokenIn( cache.sharesCached * scaleFactor_, cache.fyTokenCached * scaleFactor_, maturity - uint32(block.timestamp), // This can't be called after maturity ts, _computeG2(cache.g1Fee), _getC(), mu ) / scaleFactor_; } /// @inheritdoc IPool function maxFYTokenOut() public view override returns (uint128 fyTokenOut) { uint96 scaleFactor_ = scaleFactor; Cache memory cache = _getCache(); fyTokenOut = YieldMath.maxFYTokenOut( cache.sharesCached * scaleFactor_, cache.fyTokenCached * scaleFactor_, maturity - uint32(block.timestamp), // This can't be called after maturity ts, _computeG1(cache.g1Fee), _getC(), mu ) / scaleFactor_; } /// @inheritdoc IPool function maxBaseIn() public view override returns (uint128 baseIn) { uint96 scaleFactor_ = scaleFactor; Cache memory cache = _getCache(); uint128 sharesIn = ((YieldMath.maxSharesIn( cache.sharesCached * scaleFactor_, cache.fyTokenCached * scaleFactor_, maturity - uint32(block.timestamp), // This can't be called after maturity ts, _computeG1(cache.g1Fee), _getC(), mu ) / 1e8) * 1e8) / scaleFactor_; // Shave 8 wei/decimals to deal with precision issues on the decimal functions baseIn = _unwrapPreview(sharesIn).u128(); } /// @inheritdoc IPool function maxBaseOut() public view override returns (uint128 baseOut) { uint128 sharesOut = _getCache().sharesCached; baseOut = _unwrapPreview(sharesOut).u128(); } /// @inheritdoc IPool function invariant() public view override returns (uint128 result) { uint96 scaleFactor_ = scaleFactor; Cache memory cache = _getCache(); result = YieldMath.invariant( cache.sharesCached * scaleFactor_, cache.fyTokenCached * scaleFactor_, _totalSupply * scaleFactor_, maturity - uint32(block.timestamp), ts, _computeG2(cache.g1Fee), _getC(), mu ) / scaleFactor_; } /* WRAPPING FUNCTIONS ****************************************************************************************************************/ /// Wraps any base asset tokens found in the contract, converting them to base tokenized vault shares. /// @dev This is provided as a convenience and uses the 4626 deposit method. /// @param receiver The address to which the wrapped tokens will be sent. /// @return shares The amount of wrapped tokens sent to the receiver. function wrap(address receiver) external returns (uint256 shares) { shares = _wrap(receiver); } /// Internal function for wrapping base tokens whichwraps the entire balance of base found in this contract. /// @dev This should be overridden by modules. /// @param receiver The address the wrapped tokens should be sent. /// @return shares The amount of wrapped tokens that are sent to the receiver. function _wrap(address receiver) internal virtual returns (uint256 shares) { uint256 assets = baseToken.balanceOf(address(this)); if (assets == 0) { shares = 0; } else { shares = IERC4626(address(sharesToken)).deposit(assets, receiver); } } /// Preview how many shares will be received when depositing a given amount of base. /// @dev This should be overridden by modules. /// @param assets The amount of base tokens to preview the deposit. /// @return shares The amount of shares that would be returned from depositing. function wrapPreview(uint256 assets) external view returns (uint256 shares) { shares = _wrapPreview(assets); } /// Internal function to preview how many shares will be received when depositing a given amount of assets. /// @param assets The amount of base tokens to preview the deposit. /// @return shares The amount of shares that would be returned from depositing. function _wrapPreview(uint256 assets) internal view virtual returns (uint256 shares) { if (assets == 0) { shares = 0; } else { shares = IERC4626(address(sharesToken)).previewDeposit(assets); } } /// Unwraps base shares found unaccounted for in this contract, converting them to the base assets. /// @dev This is provided as a convenience and uses the 4626 redeem method. /// @param receiver The address to which the assets will be sent. /// @return assets The amount of asset tokens sent to the receiver. function unwrap(address receiver) external returns (uint256 assets) { assets = _unwrap(receiver); } /// Internal function for unwrapping unaccounted for base in this contract. /// @dev This should be overridden by modules. /// @param receiver The address the wrapped tokens should be sent. /// @return assets The amount of base assets sent to the receiver. function _unwrap(address receiver) internal virtual returns (uint256 assets) { uint256 surplus = _getSharesBalance() - sharesCached; if (surplus == 0) { assets = 0; } else { // The third param of the 4626 redeem fn, `owner`, is always this contract address. assets = IERC4626(address(sharesToken)).redeem(surplus, receiver, address(this)); } } /// Preview how many asset tokens will be received when unwrapping a given amount of shares. /// @param shares The amount of shares to preview a redemption. /// @return assets The amount of base tokens that would be returned from redeeming. function unwrapPreview(uint256 shares) external view returns (uint256 assets) { assets = _unwrapPreview(shares); } /// Internal function to preview how base asset tokens will be received when unwrapping a given amount of shares. /// @dev This should be overridden by modules. /// @param shares The amount of shares to preview a redemption. /// @return assets The amount of base tokens that would be returned from redeeming. function _unwrapPreview(uint256 shares) internal view virtual returns (uint256 assets) { if (shares == 0) { assets = 0; } else { assets = IERC4626(address(sharesToken)).previewRedeem(shares); } } /* BALANCES MANAGEMENT AND ADMINISTRATIVE FUNCTIONS Note: The sync() function has been discontinued and removed. *****************************************************************************************************************/ /* _____________________________________ |o o o o o o o o o o o o o o o o o| |o o o o o o o o o o o o o o o o o| ||_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|| || | | | | | | | | | | | | | | | || |o o o o o o o o o o o o o o o o o| |o o o o o o o o o o o o o o o o o| |o o o o o o o o o o o o o o o o o| |o o o o o o o o o o o o o o o o o| _|o_o_o_o_o_o_o_o_o_o_o_o_o_o_o_o_o|_ "Poolie's Abacus" - ejm */ /// Calculates cumulative ratio as of current timestamp. Can be consumed for TWAR observations. /// @dev See UniV2 implmentation: https://tinyurl.com/UniV2currentCumulativePrice /// @return currentCumulativeRatio_ is the cumulative ratio up to the current timestamp as ray. /// @return blockTimestampCurrent is the current block timestamp that the currentCumulativeRatio was computed with. function currentCumulativeRatio() external view virtual returns (uint256 currentCumulativeRatio_, uint256 blockTimestampCurrent) { blockTimestampCurrent = block.timestamp; uint256 timeElapsed; unchecked { timeElapsed = blockTimestampCurrent - blockTimestampLast; } // Multiply by 1e27 here so that r = t * y/x is a fixed point factor with 27 decimals currentCumulativeRatio_ = cumulativeRatioLast + (fyTokenCached * timeElapsed).rdiv(_mulMu(sharesCached)); } /// Update cached values and, on the first call per block, update cumulativeRatioLast. /// cumulativeRatioLast is a LAGGING, time weighted sum of the reserves ratio which is updated as follows: /// /// cumulativeRatioLast += old fyTokenReserves / old baseReserves * seconds elapsed since blockTimestampLast /// /// NOTE: baseReserves is calculated as mu * sharesReserves /// /// Example: /// First mint creates a ratio of 1:1. /// 300 seconds later a trade occurs: /// - cumulativeRatioLast is updated: 0 + 1/1 * 300 == 300 /// - sharesCached and fyTokenCached are updated with the new reserves amounts. /// - This causes the ratio to skew to 1.1 / 1. /// 200 seconds later another trade occurs: /// - NOTE: During this 200 seconds, cumulativeRatioLast == 300, which represents the "last" updated amount. /// - cumulativeRatioLast is updated: 300 + 1.1 / 1 * 200 == 520 /// - sharesCached and fyTokenCached updated accordingly...etc. /// /// @dev See UniV2 implmentation: https://tinyurl.com/UniV2UpdateCumulativePrice function _update( uint128 sharesBalance, uint128 fyBalance, uint104 sharesCached_, uint104 fyTokenCached_ ) internal { // No need to update and spend gas on SSTORE if reserves haven't changed. if (sharesBalance == sharesCached_ && fyBalance == fyTokenCached_) return; uint32 blockTimestamp = uint32(block.timestamp); uint256 timeElapsed = blockTimestamp - blockTimestampLast; // reverts on underflow uint256 oldCumulativeRatioLast = cumulativeRatioLast; uint256 newCumulativeRatioLast = oldCumulativeRatioLast; if (timeElapsed > 0 && fyTokenCached_ > 0 && sharesCached_ > 0) { // Multiply by 1e27 here so that r = t * y/x is a fixed point factor with 27 decimals newCumulativeRatioLast += (fyTokenCached_ * timeElapsed).rdiv(_mulMu(sharesCached_)); } blockTimestampLast = blockTimestamp; cumulativeRatioLast = newCumulativeRatioLast; // Update the reserves caches uint104 newSharesCached = sharesBalance.u104(); uint104 newFYTokenCached = fyBalance.u104(); sharesCached = newSharesCached; fyTokenCached = newFYTokenCached; emit Sync(newSharesCached, newFYTokenCached, newCumulativeRatioLast); } /// Exposes the 64.64 factor used for determining fees. /// A value of 1 (in 64.64) means no fees. g1 < 1 because it is used when selling base shares to the pool. /// @dev Converts state var cache.g1Fee(fp4) to a 64bit divided by 10,000 /// Useful for external contracts that need to perform calculations related to pool. /// @return a 64bit factor used for applying fees when buying fyToken/selling base. function g1() external view returns (int128) { Cache memory cache = _getCache(); return _computeG1(cache.g1Fee); } /// Returns the ratio of net proceeds after fees, for buying fyToken function _computeG1(uint16 g1Fee_) internal pure returns (int128) { return uint256(g1Fee_).divu(10000); } /// Exposes the 64.64 factor used for determining fees. /// A value of 1 means no fees. g2 > 1 because it is used when selling fyToken to the pool. /// @dev Calculated by dividing 10,000 by state var cache.g1Fee(fp4) and converting to 64bit. /// Useful for external contracts that need to perform calculations related to pool. /// @return a 64bit factor used for applying fees when selling fyToken/buying base. function g2() external view returns (int128) { Cache memory cache = _getCache(); return _computeG2(cache.g1Fee); } /// Returns the ratio of net proceeds after fees, for selling fyToken function _computeG2(uint16 g1Fee_) internal pure returns (int128) { // Divide 1 (64.64) by g1 return uint256(10000).divu(g1Fee_); } /// Returns the shares balance with the same decimals as the underlying base asset. /// @dev NOTE: If the decimals of the share token does not match the base token, then the amount of shares returned /// will be adjusted to match the decimals of the base token. /// @return The current balance of the pool's shares tokens as uint128 for consistency with other functions. function getSharesBalance() external view returns (uint128) { return _getSharesBalance(); } /// Returns the shares balance /// @dev NOTE: The decimals returned here must match the decimals of the base token. If not, then this fn should // be overriden by modules. function _getSharesBalance() internal view virtual returns (uint104) { return sharesToken.balanceOf(address(this)).u104(); } /// Returns the base balance. /// @dev Returns uint128 for backwards compatibility /// @return The current balance of the pool's base tokens. function getBaseBalance() external view returns (uint128) { return _getBaseBalance().u128(); } /// Returns the base balance function _getBaseBalance() internal view virtual returns (uint256) { return (_getSharesBalance() * _getCurrentSharePrice()) / 10**baseDecimals; } /// Returns the base token current price. /// @return The price of 1 share of a tokenized vault token in terms of its base cast as uint256. function getCurrentSharePrice() external view returns (uint256) { return _getCurrentSharePrice(); } /// Returns the base token current price. /// @dev This assumes the shares, base, and lp tokens all use the same decimals. /// This function should be overriden by modules. /// @return The price of 1 share of a tokenized vault token in terms of its base asset cast as uint256. function _getCurrentSharePrice() internal view virtual returns (uint256) { uint256 scalar = 10**baseDecimals; return IERC4626(address(sharesToken)).convertToAssets(scalar); } /// Returns current price of 1 share in 64bit. /// Useful for external contracts that need to perform calculations related to pool. /// @return The current price (as determined by the token) scalled to 18 digits and converted to 64.64. function getC() external view returns (int128) { return _getC(); } /// Returns the c based on the current price function _getC() internal view returns (int128) { return (_getCurrentSharePrice() * scaleFactor).divu(1e18); } /// Returns the all storage vars except for cumulativeRatioLast /// @return Cached shares token balance. /// @return Cached virtual FY token balance which is the actual balance plus the pool token supply. /// @return Timestamp that balances were last cached. /// @return g1Fee This is a fp4 number where 10_000 is 1. function getCache() public view virtual returns ( uint104, uint104, uint32, uint16 ) { return (sharesCached, fyTokenCached, blockTimestampLast, g1Fee); } /// Returns the all storage vars except for cumulativeRatioLast /// @dev This returns the same info as external getCache but uses a struct to help with stack too deep. /// @return cache A struct containing: /// g1Fee a fp4 number where 10_000 is 1. /// Cached base token balance. /// Cached virtual FY token balance which is the actual balance plus the pool token supply. /// Timestamp that balances were last cached. function _getCache() internal view virtual returns (Cache memory cache) { cache = Cache(g1Fee, sharesCached, fyTokenCached, blockTimestampLast); } /// The "virtual" fyToken balance, which is the actual balance plus the pool token supply. /// @dev For more explanation about using the LP tokens as part of the virtual reserves see: /// https://hackmd.io/lRZ4mgdrRgOpxZQXqKYlFw /// Returns uint128 for backwards compatibility /// @return The current balance of the pool's fyTokens plus the current balance of the pool's /// total supply of LP tokens as a uint104 function getFYTokenBalance() public view virtual override returns (uint128) { return _getFYTokenBalance(); } /// Returns the "virtual" fyToken balance, which is the real balance plus the pool token supply. function _getFYTokenBalance() internal view returns (uint104) { return (fyToken.balanceOf(address(this)) + _totalSupply).u104(); } /// Returns mu multipled by given amount. /// @param amount Amount as standard fp number. /// @return product Return standard fp number retaining decimals of provided amount. function _mulMu(uint256 amount) internal view returns (uint256 product) { product = mu.mulu(amount); } /// Retrieve any shares tokens not accounted for in the cache. /// @param to Address of the recipient of the shares tokens. /// @return retrieved The amount of shares tokens sent. function retrieveShares(address to) external virtual override returns (uint128 retrieved) { retrieved = _getSharesBalance() - sharesCached; // Cache can never be above balances sharesToken.safeTransfer(to, retrieved); } /// Retrieve all base tokens found in this contract. /// @param to Address of the recipient of the base tokens. /// @return retrieved The amount of base tokens sent. function retrieveBase(address to) external virtual override returns (uint128 retrieved) { // This and most other pools do not keep any baseTokens, so retrieve everything. // Note: For PoolNonTv, baseToken == sharesToken so must override this fn. retrieved = baseToken.balanceOf(address(this)).u128(); baseToken.safeTransfer(to, retrieved); } /// Retrieve any fyTokens not accounted for in the cache. /// @param to Address of the recipient of the fyTokens. /// @return retrieved The amount of fyTokens sent. function retrieveFYToken(address to) external virtual override returns (uint128 retrieved) { // related: https://twitter.com/transmissions11/status/1505994136389754880?s=20&t=1H6gvzl7DJLBxXqnhTuOVw retrieved = _getFYTokenBalance() - fyTokenCached; // Cache can never be above balances fyToken.safeTransfer(to, retrieved); // Now the balances match the cache, so no need to update the TWAR } /// Sets g1 as an fp4, g1 <= 1.0 /// @dev These numbers are converted to 64.64 and used to calculate g1 by dividing them, or g2 from 1/g1 function setFees(uint16 g1Fee_) public auth { if (g1Fee_ > 10000) { revert InvalidFee(g1Fee_); } g1Fee = g1Fee_; emit FeesSet(g1Fee_); } /// Returns baseToken. /// @dev This has been deprecated and may be removed in future pools. /// @return baseToken The base token for this pool. The base of the shares and the fyToken. function base() external view returns (IERC20) { // Returns IERC20 instead of IERC20Like (IERC20Metadata) for backwards compatability. return IERC20(address(baseToken)); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.15; import "./PoolEvents.sol"; import "./PoolErrors.sol"; import {Cast} from "@yield-protocol/utils-v2/src/utils/Cast.sol"; import {Exp64x64} from "../Exp64x64.sol"; import {Math64x64} from "../Math64x64.sol"; import {YieldMath} from "../YieldMath.sol"; import {Math} from "@yield-protocol/utils-v2/src/utils/Math.sol"; import {IPool} from "../interfaces/IPool.sol"; import {IERC4626} from "../interfaces/IERC4626.sol"; import {IMaturingToken} from "../interfaces/IMaturingToken.sol"; import {ERC20Permit} from "@yield-protocol/utils-v2/src/token/ERC20Permit.sol"; import {AccessControl} from "@yield-protocol/utils-v2/src/access/AccessControl.sol"; import {ERC20, IERC20Metadata as IERC20Like, IERC20} from "@yield-protocol/utils-v2/src/token/ERC20.sol"; import {TransferHelper} from "@yield-protocol/utils-v2/src/token/TransferHelper.sol";
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.15; /* __ ___ _ _ \ \ / (_) | | | | ███████╗██╗ ██╗██████╗ ██████╗ ██╗ ██╗██╗ ██╗ ██████╗ ██╗ ██╗ \ \_/ / _ ___| | __| | ██╔════╝╚██╗██╔╝██╔══██╗██╔════╝ ██║ ██║╚██╗██╔╝██╔════╝ ██║ ██║ \ / | |/ _ \ |/ _` | █████╗ ╚███╔╝ ██████╔╝███████╗ ███████║ ╚███╔╝ ███████╗ ███████║ | | | | __/ | (_| | ██╔══╝ ██╔██╗ ██╔═══╝ ██╔═══██╗╚════██║ ██╔██╗ ██╔═══██╗╚════██║ |_| |_|\___|_|\__,_| ███████╗██╔╝ ██╗██║ ╚██████╔╝ ██║██╔╝ ██╗╚██████╔╝ ██║ yieldprotocol.com ╚══════╝╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ Gas optimized math library custom-built by ABDK -- Copyright © 2019 */ import "./Math64x64.sol"; library Exp64x64 { using Math64x64 for int128; /// @dev Raises a 64.64 number to the power of another 64.64 number /// x^y = 2^(y*log_2(x)) /// https://ethereum.stackexchange.com/questions/79903/exponential-function-with-fractional-numbers function pow(int128 x, int128 y) internal pure returns (int128) { return y.mul(x.log_2()).exp_2(); } /* Mikhail Vladimirov, [Jul 6, 2022 at 12:26:12 PM (Jul 6, 2022 at 12:28:29 PM)]: In simple words, when have an n-bits wide number x and raise it to a power α, then the result would be α*n bits wide. This, if α<1, the result will loose precision, and if α>1, the result could exceed range. So, the pow function multiplies the result by 2^(n * (1 - α)). We have: x ∈ [0; 2^n) x^α ∈ [0; 2^(α*n)) x^α * 2^(n * (1 - α)) ∈ [0; 2^(α*n) * 2^(n * (1 - α))) = [0; 2^(α*n + n * (1 - α))) = [0; 2^(n * (α + (1 - α)))) = [0; 2^n) So the normalization returns the result back into the proper range. Now note, that: pow (pow (x, α), 1/α) = pow (x^α * 2^(n * (1 -α)) , 1/α) = (x^α * 2^(n * (1 -α)))^(1/α) * 2^(n * (1 -1/α)) = x^(α * (1/α)) * 2^(n * (1 -α) * (1/α)) * 2^(n * (1 -1/α)) = x * 2^(n * (1/α -1)) * 2^(n * (1 -1/α)) = x * 2^(n * (1/α -1) + n * (1 -1/α)) = x So, for formulas that look like: (a x^α + b y^α + ...)^(1/α) The pow function could be used instead of normal power. */ /// @dev Raise given number x into power specified as a simple fraction y/z and then /// multiply the result by the normalization factor 2^(128 /// (1 - y/z)). /// Revert if z is zero, or if both x and y are zeros. /// @param x number to raise into given power y/z -- integer /// @param y numerator of the power to raise x into -- 64.64 /// @param z denominator of the power to raise x into -- 64.64 /// @return x raised into power y/z and then multiplied by 2^(128 * (1 - y/z)) -- integer function pow( uint128 x, uint128 y, uint128 z ) internal pure returns (uint128) { unchecked { require(z != 0); if (x == 0) { require(y != 0); return 0; } else { uint256 l = (uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - log_2(x)) * y) / z; if (l > 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) return 0; else return pow_2(uint128(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - l)); } } } /// @dev Calculate base 2 logarithm of an unsigned 128-bit integer number. Revert /// in case x is zero. /// @param x number to calculate base 2 logarithm of /// @return base 2 logarithm of x, multiplied by 2^121 function log_2(uint128 x) internal pure returns (uint128) { unchecked { require(x != 0); uint256 b = x; uint256 l = 0xFE000000000000000000000000000000; if (b < 0x10000000000000000) { l -= 0x80000000000000000000000000000000; b <<= 64; } if (b < 0x1000000000000000000000000) { l -= 0x40000000000000000000000000000000; b <<= 32; } if (b < 0x10000000000000000000000000000) { l -= 0x20000000000000000000000000000000; b <<= 16; } if (b < 0x1000000000000000000000000000000) { l -= 0x10000000000000000000000000000000; b <<= 8; } if (b < 0x10000000000000000000000000000000) { l -= 0x8000000000000000000000000000000; b <<= 4; } if (b < 0x40000000000000000000000000000000) { l -= 0x4000000000000000000000000000000; b <<= 2; } if (b < 0x80000000000000000000000000000000) { l -= 0x2000000000000000000000000000000; b <<= 1; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x1000000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x800000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x400000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x200000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x100000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x80000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x40000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x20000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x10000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x8000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x4000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x2000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x1000000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x800000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x400000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x200000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x100000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x80000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x40000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x20000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x10000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x8000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x4000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x2000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x1000000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x800000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x400000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x200000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x100000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x80000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x40000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x20000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x10000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x8000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x4000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x2000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x1000000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x800000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x400000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x200000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x100000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x80000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x40000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x20000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x10000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x8000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x4000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x2000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x1000000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x800000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x400000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x200000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x100000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x80000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x40000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x20000000000000000; } b = (b * b) >> 127; if (b >= 0x100000000000000000000000000000000) { b >>= 1; l |= 0x10000000000000000; } /* b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x8000000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x4000000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x2000000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x1000000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x800000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x400000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x200000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x100000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x80000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x40000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x20000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x10000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x8000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x4000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x2000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x1000000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x800000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x400000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x200000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x100000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x80000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x40000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x20000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x10000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x8000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x4000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x2000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x1000000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x800000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x400000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x200000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x100000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x80000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x40000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x20000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x10000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x8000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x4000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x2000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x1000000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x800000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x400000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x200000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x100000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x80000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x40000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x20000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x10000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x8000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x4000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x2000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x1000;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x800;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x400;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x200;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x100;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x80;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x40;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x20;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x10;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x8;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x4;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) {b >>= 1; l |= 0x2;} b = b * b >> 127; if(b >= 0x100000000000000000000000000000000) l |= 0x1; */ return uint128(l); } } /// @dev Calculate 2 raised into given power. /// @param x power to raise 2 into, multiplied by 2^121 /// @return 2 raised into given power function pow_2(uint128 x) internal pure returns (uint128) { unchecked { uint256 r = 0x80000000000000000000000000000000; if (x & 0x1000000000000000000000000000000 > 0) r = (r * 0xb504f333f9de6484597d89b3754abe9f) >> 127; if (x & 0x800000000000000000000000000000 > 0) r = (r * 0x9837f0518db8a96f46ad23182e42f6f6) >> 127; if (x & 0x400000000000000000000000000000 > 0) r = (r * 0x8b95c1e3ea8bd6e6fbe4628758a53c90) >> 127; if (x & 0x200000000000000000000000000000 > 0) r = (r * 0x85aac367cc487b14c5c95b8c2154c1b2) >> 127; if (x & 0x100000000000000000000000000000 > 0) r = (r * 0x82cd8698ac2ba1d73e2a475b46520bff) >> 127; if (x & 0x80000000000000000000000000000 > 0) r = (r * 0x8164d1f3bc0307737be56527bd14def4) >> 127; if (x & 0x40000000000000000000000000000 > 0) r = (r * 0x80b1ed4fd999ab6c25335719b6e6fd20) >> 127; if (x & 0x20000000000000000000000000000 > 0) r = (r * 0x8058d7d2d5e5f6b094d589f608ee4aa2) >> 127; if (x & 0x10000000000000000000000000000 > 0) r = (r * 0x802c6436d0e04f50ff8ce94a6797b3ce) >> 127; if (x & 0x8000000000000000000000000000 > 0) r = (r * 0x8016302f174676283690dfe44d11d008) >> 127; if (x & 0x4000000000000000000000000000 > 0) r = (r * 0x800b179c82028fd0945e54e2ae18f2f0) >> 127; if (x & 0x2000000000000000000000000000 > 0) r = (r * 0x80058baf7fee3b5d1c718b38e549cb93) >> 127; if (x & 0x1000000000000000000000000000 > 0) r = (r * 0x8002c5d00fdcfcb6b6566a58c048be1f) >> 127; if (x & 0x800000000000000000000000000 > 0) r = (r * 0x800162e61bed4a48e84c2e1a463473d9) >> 127; if (x & 0x400000000000000000000000000 > 0) r = (r * 0x8000b17292f702a3aa22beacca949013) >> 127; if (x & 0x200000000000000000000000000 > 0) r = (r * 0x800058b92abbae02030c5fa5256f41fe) >> 127; if (x & 0x100000000000000000000000000 > 0) r = (r * 0x80002c5c8dade4d71776c0f4dbea67d6) >> 127; if (x & 0x80000000000000000000000000 > 0) r = (r * 0x8000162e44eaf636526be456600bdbe4) >> 127; if (x & 0x40000000000000000000000000 > 0) r = (r * 0x80000b1721fa7c188307016c1cd4e8b6) >> 127; if (x & 0x20000000000000000000000000 > 0) r = (r * 0x8000058b90de7e4cecfc487503488bb1) >> 127; if (x & 0x10000000000000000000000000 > 0) r = (r * 0x800002c5c8678f36cbfce50a6de60b14) >> 127; if (x & 0x8000000000000000000000000 > 0) r = (r * 0x80000162e431db9f80b2347b5d62e516) >> 127; if (x & 0x4000000000000000000000000 > 0) r = (r * 0x800000b1721872d0c7b08cf1e0114152) >> 127; if (x & 0x2000000000000000000000000 > 0) r = (r * 0x80000058b90c1aa8a5c3736cb77e8dff) >> 127; if (x & 0x1000000000000000000000000 > 0) r = (r * 0x8000002c5c8605a4635f2efc2362d978) >> 127; if (x & 0x800000000000000000000000 > 0) r = (r * 0x800000162e4300e635cf4a109e3939bd) >> 127; if (x & 0x400000000000000000000000 > 0) r = (r * 0x8000000b17217ff81bef9c551590cf83) >> 127; if (x & 0x200000000000000000000000 > 0) r = (r * 0x800000058b90bfdd4e39cd52c0cfa27c) >> 127; if (x & 0x100000000000000000000000 > 0) r = (r * 0x80000002c5c85fe6f72d669e0e76e411) >> 127; if (x & 0x80000000000000000000000 > 0) r = (r * 0x8000000162e42ff18f9ad35186d0df28) >> 127; if (x & 0x40000000000000000000000 > 0) r = (r * 0x80000000b17217f84cce71aa0dcfffe7) >> 127; if (x & 0x20000000000000000000000 > 0) r = (r * 0x8000000058b90bfc07a77ad56ed22aaa) >> 127; if (x & 0x10000000000000000000000 > 0) r = (r * 0x800000002c5c85fdfc23cdead40da8d6) >> 127; if (x & 0x8000000000000000000000 > 0) r = (r * 0x80000000162e42fefc25eb1571853a66) >> 127; if (x & 0x4000000000000000000000 > 0) r = (r * 0x800000000b17217f7d97f692baacded5) >> 127; if (x & 0x2000000000000000000000 > 0) r = (r * 0x80000000058b90bfbead3b8b5dd254d7) >> 127; if (x & 0x1000000000000000000000 > 0) r = (r * 0x8000000002c5c85fdf4eedd62f084e67) >> 127; if (x & 0x800000000000000000000 > 0) r = (r * 0x800000000162e42fefa58aef378bf586) >> 127; if (x & 0x400000000000000000000 > 0) r = (r * 0x8000000000b17217f7d24a78a3c7ef02) >> 127; if (x & 0x200000000000000000000 > 0) r = (r * 0x800000000058b90bfbe9067c93e474a6) >> 127; if (x & 0x100000000000000000000 > 0) r = (r * 0x80000000002c5c85fdf47b8e5a72599f) >> 127; if (x & 0x80000000000000000000 > 0) r = (r * 0x8000000000162e42fefa3bdb315934a2) >> 127; if (x & 0x40000000000000000000 > 0) r = (r * 0x80000000000b17217f7d1d7299b49c46) >> 127; if (x & 0x20000000000000000000 > 0) r = (r * 0x8000000000058b90bfbe8e9a8d1c4ea0) >> 127; if (x & 0x10000000000000000000 > 0) r = (r * 0x800000000002c5c85fdf4745969ea76f) >> 127; if (x & 0x8000000000000000000 > 0) r = (r * 0x80000000000162e42fefa3a0df5373bf) >> 127; if (x & 0x4000000000000000000 > 0) r = (r * 0x800000000000b17217f7d1cff4aac1e1) >> 127; if (x & 0x2000000000000000000 > 0) r = (r * 0x80000000000058b90bfbe8e7db95a2f1) >> 127; if (x & 0x1000000000000000000 > 0) r = (r * 0x8000000000002c5c85fdf473e61ae1f8) >> 127; if (x & 0x800000000000000000 > 0) r = (r * 0x800000000000162e42fefa39f121751c) >> 127; if (x & 0x400000000000000000 > 0) r = (r * 0x8000000000000b17217f7d1cf815bb96) >> 127; if (x & 0x200000000000000000 > 0) r = (r * 0x800000000000058b90bfbe8e7bec1e0d) >> 127; if (x & 0x100000000000000000 > 0) r = (r * 0x80000000000002c5c85fdf473dee5f17) >> 127; if (x & 0x80000000000000000 > 0) r = (r * 0x8000000000000162e42fefa39ef5438f) >> 127; if (x & 0x40000000000000000 > 0) r = (r * 0x80000000000000b17217f7d1cf7a26c8) >> 127; if (x & 0x20000000000000000 > 0) r = (r * 0x8000000000000058b90bfbe8e7bcf4a4) >> 127; if (x & 0x10000000000000000 > 0) r = (r * 0x800000000000002c5c85fdf473de72a2) >> 127; /* if(x & 0x8000000000000000 > 0) r = r * 0x80000000000000162e42fefa39ef3765 >> 127; if(x & 0x4000000000000000 > 0) r = r * 0x800000000000000b17217f7d1cf79b37 >> 127; if(x & 0x2000000000000000 > 0) r = r * 0x80000000000000058b90bfbe8e7bcd7d >> 127; if(x & 0x1000000000000000 > 0) r = r * 0x8000000000000002c5c85fdf473de6b6 >> 127; if(x & 0x800000000000000 > 0) r = r * 0x800000000000000162e42fefa39ef359 >> 127; if(x & 0x400000000000000 > 0) r = r * 0x8000000000000000b17217f7d1cf79ac >> 127; if(x & 0x200000000000000 > 0) r = r * 0x800000000000000058b90bfbe8e7bcd6 >> 127; if(x & 0x100000000000000 > 0) r = r * 0x80000000000000002c5c85fdf473de6a >> 127; if(x & 0x80000000000000 > 0) r = r * 0x8000000000000000162e42fefa39ef35 >> 127; if(x & 0x40000000000000 > 0) r = r * 0x80000000000000000b17217f7d1cf79a >> 127; if(x & 0x20000000000000 > 0) r = r * 0x8000000000000000058b90bfbe8e7bcd >> 127; if(x & 0x10000000000000 > 0) r = r * 0x800000000000000002c5c85fdf473de6 >> 127; if(x & 0x8000000000000 > 0) r = r * 0x80000000000000000162e42fefa39ef3 >> 127; if(x & 0x4000000000000 > 0) r = r * 0x800000000000000000b17217f7d1cf79 >> 127; if(x & 0x2000000000000 > 0) r = r * 0x80000000000000000058b90bfbe8e7bc >> 127; if(x & 0x1000000000000 > 0) r = r * 0x8000000000000000002c5c85fdf473de >> 127; if(x & 0x800000000000 > 0) r = r * 0x800000000000000000162e42fefa39ef >> 127; if(x & 0x400000000000 > 0) r = r * 0x8000000000000000000b17217f7d1cf7 >> 127; if(x & 0x200000000000 > 0) r = r * 0x800000000000000000058b90bfbe8e7b >> 127; if(x & 0x100000000000 > 0) r = r * 0x80000000000000000002c5c85fdf473d >> 127; if(x & 0x80000000000 > 0) r = r * 0x8000000000000000000162e42fefa39e >> 127; if(x & 0x40000000000 > 0) r = r * 0x80000000000000000000b17217f7d1cf >> 127; if(x & 0x20000000000 > 0) r = r * 0x8000000000000000000058b90bfbe8e7 >> 127; if(x & 0x10000000000 > 0) r = r * 0x800000000000000000002c5c85fdf473 >> 127; if(x & 0x8000000000 > 0) r = r * 0x80000000000000000000162e42fefa39 >> 127; if(x & 0x4000000000 > 0) r = r * 0x800000000000000000000b17217f7d1c >> 127; if(x & 0x2000000000 > 0) r = r * 0x80000000000000000000058b90bfbe8e >> 127; if(x & 0x1000000000 > 0) r = r * 0x8000000000000000000002c5c85fdf47 >> 127; if(x & 0x800000000 > 0) r = r * 0x800000000000000000000162e42fefa3 >> 127; if(x & 0x400000000 > 0) r = r * 0x8000000000000000000000b17217f7d1 >> 127; if(x & 0x200000000 > 0) r = r * 0x800000000000000000000058b90bfbe8 >> 127; if(x & 0x100000000 > 0) r = r * 0x80000000000000000000002c5c85fdf4 >> 127; if(x & 0x80000000 > 0) r = r * 0x8000000000000000000000162e42fefa >> 127; if(x & 0x40000000 > 0) r = r * 0x80000000000000000000000b17217f7d >> 127; if(x & 0x20000000 > 0) r = r * 0x8000000000000000000000058b90bfbe >> 127; if(x & 0x10000000 > 0) r = r * 0x800000000000000000000002c5c85fdf >> 127; if(x & 0x8000000 > 0) r = r * 0x80000000000000000000000162e42fef >> 127; if(x & 0x4000000 > 0) r = r * 0x800000000000000000000000b17217f7 >> 127; if(x & 0x2000000 > 0) r = r * 0x80000000000000000000000058b90bfb >> 127; if(x & 0x1000000 > 0) r = r * 0x8000000000000000000000002c5c85fd >> 127; if(x & 0x800000 > 0) r = r * 0x800000000000000000000000162e42fe >> 127; if(x & 0x400000 > 0) r = r * 0x8000000000000000000000000b17217f >> 127; if(x & 0x200000 > 0) r = r * 0x800000000000000000000000058b90bf >> 127; if(x & 0x100000 > 0) r = r * 0x80000000000000000000000002c5c85f >> 127; if(x & 0x80000 > 0) r = r * 0x8000000000000000000000000162e42f >> 127; if(x & 0x40000 > 0) r = r * 0x80000000000000000000000000b17217 >> 127; if(x & 0x20000 > 0) r = r * 0x8000000000000000000000000058b90b >> 127; if(x & 0x10000 > 0) r = r * 0x800000000000000000000000002c5c85 >> 127; if(x & 0x8000 > 0) r = r * 0x80000000000000000000000000162e42 >> 127; if(x & 0x4000 > 0) r = r * 0x800000000000000000000000000b1721 >> 127; if(x & 0x2000 > 0) r = r * 0x80000000000000000000000000058b90 >> 127; if(x & 0x1000 > 0) r = r * 0x8000000000000000000000000002c5c8 >> 127; if(x & 0x800 > 0) r = r * 0x800000000000000000000000000162e4 >> 127; if(x & 0x400 > 0) r = r * 0x8000000000000000000000000000b172 >> 127; if(x & 0x200 > 0) r = r * 0x800000000000000000000000000058b9 >> 127; if(x & 0x100 > 0) r = r * 0x80000000000000000000000000002c5c >> 127; if(x & 0x80 > 0) r = r * 0x8000000000000000000000000000162e >> 127; if(x & 0x40 > 0) r = r * 0x80000000000000000000000000000b17 >> 127; if(x & 0x20 > 0) r = r * 0x8000000000000000000000000000058b >> 127; if(x & 0x10 > 0) r = r * 0x800000000000000000000000000002c5 >> 127; if(x & 0x8 > 0) r = r * 0x80000000000000000000000000000162 >> 127; if(x & 0x4 > 0) r = r * 0x800000000000000000000000000000b1 >> 127; if(x & 0x2 > 0) r = r * 0x80000000000000000000000000000058 >> 127; if(x & 0x1 > 0) r = r * 0x8000000000000000000000000000002c >> 127; */ r >>= 127 - (x >> 121); return uint128(r); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.13; library Cast { ///@dev library for safe casting of value types function b12(bytes32 x) internal pure returns (bytes12 y) { require(bytes32(y = bytes12(x)) == x, "Cast overflow"); } function b6(bytes32 x) internal pure returns (bytes6 y) { require(bytes32(y = bytes6(x)) == x, "Cast overflow"); } function u256(int256 x) internal pure returns (uint256 y) { require(x >= 0, "Cast overflow"); y = uint256(x); } function i256(uint256 x) internal pure returns (int256 y) { require(x <= uint256(type(int256).max), "Cast overflow"); y = int256(x); } function u128(uint256 x) internal pure returns (uint128 y) { require(x <= type(uint128).max, "Cast overflow"); y = uint128(x); } function u128(int256 x) internal pure returns (uint128 y) { require(x >= 0, "Cast overflow"); y = uint128(uint256(x)); } function i128(uint256 x) internal pure returns (int128) { require(x <= uint256(int256(type(int128).max)), "Cast overflow"); return int128(int256(x)); } function i128(int256 x) internal pure returns (int128) { require(x <= type(int128).max, "Cast overflow"); require(x >= type(int128).min, "Cast overflow"); return int128(x); } function u112(uint256 x) internal pure returns (uint112 y) { require(x <= type(uint112).max, "Cast overflow"); y = uint112(x); } function u104(uint256 x) internal pure returns (uint104 y) { require(x <= type(uint104).max, "Cast overflow"); y = uint104(x); } function u96(uint256 x) internal pure returns (uint96 y) { require(x <= type(uint96).max, "Cast overflow"); y = uint96(x); } function u32(uint256 x) internal pure returns (uint32 y) { require(x <= type(uint32).max, "Cast overflow"); y = uint32(x); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.13; library Math { // Taken from https://github.com/usmfum/USM/blob/master/src/WadMath.sol /// @dev Multiply an amount by a fixed point factor with 18 decimals, rounds down. function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x * y; unchecked { z /= 1e18; } } // Taken from https://github.com/usmfum/USM/blob/master/src/WadMath.sol /// @dev Multiply x and y, with y being fixed point. If both are integers, the result is a fixed point factor. Rounds up. function wmulup(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x * y + 1e18 - 1; // Rounds up. So (again imagining 2 decimal places): unchecked { z /= 1e18; } // 383 (3.83) * 235 (2.35) -> 90005 (9.0005), + 99 (0.0099) -> 90104, / 100 -> 901 (9.01). } // Taken from https://github.com/usmfum/USM/blob/master/src/WadMath.sol /// @dev Divide an amount by a fixed point factor with 18 decimals function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = (x * 1e18) / y; } // Taken from https://github.com/usmfum/USM/blob/master/src/WadMath.sol /// @dev Divide x and y, with y being fixed point. If both are integers, the result is a fixed point factor. Rounds up. function wdivup(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x * 1e18 + y; // 101 (1.01) / 1000 (10) -> (101 * 100 + 1000 - 1) / 1000 -> 11 (0.11 = 0.101 rounded up). unchecked { z -= 1; } // Can do unchecked subtraction since division in next line will catch y = 0 case anyway z /= y; } // Taken from https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol /// @dev $x ^ $n; $x is 18-decimals fixed point number function wpow(uint256 x, uint256 n) internal pure returns (uint256 z) { uint256 baseUnit = 1e18; assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := baseUnit } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store baseUnit in z for now. z := baseUnit } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, baseUnit) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, baseUnit) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, baseUnit) } } } } } /// @dev Divide an amount by a fixed point factor with 27 decimals function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = (x * 1e27) / y; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.15; /* __ ___ _ _ \ \ / (_) | | | | ███╗ ███╗ █████╗ ████████╗██╗ ██╗ ██████╗ ██╗ ██╗██╗ ██╗ ██████╗ ██╗ ██╗ \ \_/ / _ ___| | __| | ████╗ ████║██╔══██╗╚══██╔══╝██║ ██║██╔════╝ ██║ ██║╚██╗██╔╝██╔════╝ ██║ ██║ \ / | |/ _ \ |/ _` | ██╔████╔██║███████║ ██║ ███████║███████╗ ███████║ ╚███╔╝ ███████╗ ███████║ | | | | __/ | (_| | ██║╚██╔╝██║██╔══██║ ██║ ██╔══██║██╔═══██╗╚════██║ ██╔██╗ ██╔═══██╗╚════██║ |_| |_|\___|_|\__,_| ██║ ╚═╝ ██║██║ ██║ ██║ ██║ ██║╚██████╔╝ ██║██╔╝ ██╗╚██████╔╝ ██║ yieldprotocol.com ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ */ /// Smart contract library of mathematical functions operating with signed /// 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is /// basically a simple fraction whose numerator is signed 128-bit integer and /// denominator is 2^64. As long as denominator is always the same, there is no /// need to store it, thus in Solidity signed 64.64-bit fixed point numbers are /// represented by int128 type holding only the numerator. /// @title Math64x64.sol /// @author Mikhail Vladimirov - ABDK Consulting /// https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol library Math64x64 { /* CONVERTERS ******************************************************************************************************************/ /* * Minimum value signed 64.64-bit fixed point number may have. */ int128 private constant MIN_64x64 = -0x80000000000000000000000000000000; /* * Maximum value signed 64.64-bit fixed point number may have. */ int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; /// @dev Convert signed 256-bit integer number into signed 64.64-bit fixed point /// number. Revert on overflow. /// @param x signed 256-bit integer number /// @return signed 64.64-bit fixed point number function fromInt(int256 x) internal pure returns (int128) { unchecked { require(x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF); return int128(x << 64); } } /// @dev Convert signed 64.64 fixed point number into signed 64-bit integer number rounding down. /// @param x signed 64.64-bit fixed point number /// @return signed 64-bit integer number function toInt(int128 x) internal pure returns (int64) { unchecked { return int64(x >> 64); } } /// @dev Convert unsigned 256-bit integer number into signed 64.64-bit fixed point number. Revert on overflow. /// @param x unsigned 256-bit integer number /// @return signed 64.64-bit fixed point number function fromUInt(uint256 x) internal pure returns (int128) { unchecked { require(x <= 0x7FFFFFFFFFFFFFFF); return int128(int256(x << 64)); } } /// @dev Convert signed 64.64 fixed point number into unsigned 64-bit integer number rounding down. /// Reverts on underflow. /// @param x signed 64.64-bit fixed point number /// @return unsigned 64-bit integer number function toUInt(int128 x) internal pure returns (uint64) { unchecked { require(x >= 0); return uint64(uint128(x >> 64)); } } /// @dev Convert signed 128.128 fixed point number into signed 64.64-bit fixed point number rounding down. /// Reverts on overflow. /// @param x signed 128.128-bin fixed point number /// @return signed 64.64-bit fixed point number function from128x128(int256 x) internal pure returns (int128) { unchecked { int256 result = x >> 64; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } } /// @dev Convert signed 64.64 fixed point number into signed 128.128 fixed point number. /// @param x signed 64.64-bit fixed point number /// @return signed 128.128 fixed point number function to128x128(int128 x) internal pure returns (int256) { unchecked { return int256(x) << 64; } } /* OPERATIONS ******************************************************************************************************************/ /// @dev Calculate x + y. Revert on overflow. /// @param x signed 64.64-bit fixed point number /// @param y signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function add(int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) + y; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } } /// @dev Calculate x - y. Revert on overflow. /// @param x signed 64.64-bit fixed point number /// @param y signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function sub(int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) - y; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } } /// @dev Calculate x///y rounding down. Revert on overflow. /// @param x signed 64.64-bit fixed point number /// @param y signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function mul(int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = (int256(x) * y) >> 64; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } } /// @dev Calculate x * y rounding towards zero, where x is signed 64.64 fixed point /// number and y is signed 256-bit integer number. Revert on overflow. /// @param x signed 64.64 fixed point number /// @param y signed 256-bit integer number /// @return signed 256-bit integer number function muli(int128 x, int256 y) internal pure returns (int256) { //NOTE: This reverts if y == type(int128).min unchecked { if (x == MIN_64x64) { require( y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF && y <= 0x1000000000000000000000000000000000000000000000000 ); return -y << 63; } else { bool negativeResult = false; if (x < 0) { x = -x; negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint256 absoluteResult = mulu(x, uint256(y)); if (negativeResult) { require(absoluteResult <= 0x8000000000000000000000000000000000000000000000000000000000000000); return -int256(absoluteResult); // We rely on overflow behavior here } else { require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int256(absoluteResult); } } } } /// @dev Calculate x * y rounding down, where x is signed 64.64 fixed point number /// and y is unsigned 256-bit integer number. Revert on overflow. /// @param x signed 64.64 fixed point number /// @param y unsigned 256-bit integer number /// @return unsigned 256-bit integer number function mulu(int128 x, uint256 y) internal pure returns (uint256) { unchecked { if (y == 0) return 0; require(x >= 0); uint256 lo = (uint256(int256(x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64; uint256 hi = uint256(int256(x)) * (y >> 128); require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); hi <<= 64; require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo); return hi + lo; } } /// @dev Calculate x / y rounding towards zero. Revert on overflow or when y is zero. /// @param x signed 64.64-bit fixed point number /// @param y signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function div(int128 x, int128 y) internal pure returns (int128) { unchecked { require(y != 0); int256 result = (int256(x) << 64) / y; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } } /// @dev Calculate x / y rounding towards zero, where x and y are signed 256-bit /// integer numbers. Revert on overflow or when y is zero. /// @param x signed 256-bit integer number /// @param y signed 256-bit integer number /// @return signed 64.64-bit fixed point number function divi(int256 x, int256 y) internal pure returns (int128) { unchecked { require(y != 0); bool negativeResult = false; if (x < 0) { x = -x; // We rely on overflow behavior here negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint128 absoluteResult = divuu(uint256(x), uint256(y)); if (negativeResult) { require(absoluteResult <= 0x80000000000000000000000000000000); return -int128(absoluteResult); // We rely on overflow behavior here } else { require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int128(absoluteResult); // We rely on overflow behavior here } } } /// @dev Calculate x / y rounding towards zero, where x and y are unsigned 256-bit /// integer numbers. Revert on overflow or when y is zero. /// @param x unsigned 256-bit integer number /// @param y unsigned 256-bit integer number /// @return signed 64.64-bit fixed point number function divu(uint256 x, uint256 y) internal pure returns (int128) { unchecked { require(y != 0); uint128 result = divuu(x, y); require(result <= uint128(MAX_64x64)); return int128(result); } } /// @dev Calculate -x. Revert on overflow. /// @param x signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function neg(int128 x) internal pure returns (int128) { unchecked { require(x != MIN_64x64); return -x; } } /// @dev Calculate |x|. Revert on overflow. /// @param x signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function abs(int128 x) internal pure returns (int128) { unchecked { require(x != MIN_64x64); return x < 0 ? -x : x; } } /// @dev Calculate 1 / x rounding towards zero. Revert on overflow or when x is ///zero. /// @param x signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function inv(int128 x) internal pure returns (int128) { unchecked { require(x != 0); int256 result = int256(0x100000000000000000000000000000000) / x; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } } /// @dev Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down. /// @param x signed 64.64-bit fixed point number /// @param y signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function avg(int128 x, int128 y) internal pure returns (int128) { unchecked { return int128((int256(x) + int256(y)) >> 1); } } /// @dev Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down. /// Revert on overflow or in case x * y is negative. /// @param x signed 64.64-bit fixed point number /// @param y signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function gavg(int128 x, int128 y) internal pure returns (int128) { unchecked { int256 m = int256(x) * int256(y); require(m >= 0); require(m < 0x4000000000000000000000000000000000000000000000000000000000000000); return int128(sqrtu(uint256(m))); } } /// @dev Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number /// and y is unsigned 256-bit integer number. Revert on overflow. /// also see:https://hackmd.io/gbnqA3gCTR6z-F0HHTxF-A#33-Normalized-Fractional-Exponentiation /// @param x signed 64.64-bit fixed point number /// @param y uint256 value /// @return signed 64.64-bit fixed point number function pow(int128 x, uint256 y) internal pure returns (int128) { unchecked { bool negative = x < 0 && y & 1 == 1; uint256 absX = uint128(x < 0 ? -x : x); uint256 absResult; absResult = 0x100000000000000000000000000000000; if (absX <= 0x10000000000000000) { absX <<= 63; while (y != 0) { if (y & 0x1 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; if (y & 0x2 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; if (y & 0x4 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; if (y & 0x8 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; y >>= 4; } absResult >>= 64; } else { uint256 absXShift = 63; if (absX < 0x1000000000000000000000000) { absX <<= 32; absXShift -= 32; } if (absX < 0x10000000000000000000000000000) { absX <<= 16; absXShift -= 16; } if (absX < 0x1000000000000000000000000000000) { absX <<= 8; absXShift -= 8; } if (absX < 0x10000000000000000000000000000000) { absX <<= 4; absXShift -= 4; } if (absX < 0x40000000000000000000000000000000) { absX <<= 2; absXShift -= 2; } if (absX < 0x80000000000000000000000000000000) { absX <<= 1; absXShift -= 1; } uint256 resultShift = 0; while (y != 0) { require(absXShift < 64); if (y & 0x1 != 0) { absResult = (absResult * absX) >> 127; resultShift += absXShift; if (absResult > 0x100000000000000000000000000000000) { absResult >>= 1; resultShift += 1; } } absX = (absX * absX) >> 127; absXShift <<= 1; if (absX >= 0x100000000000000000000000000000000) { absX >>= 1; absXShift += 1; } y >>= 1; } require(resultShift < 64); absResult >>= 64 - resultShift; } int256 result = negative ? -int256(absResult) : int256(absResult); require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } } /// @dev Calculate sqrt (x) rounding down. Revert if x < 0. /// @param x signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function sqrt(int128 x) internal pure returns (int128) { unchecked { require(x >= 0); return int128(sqrtu(uint256(int256(x)) << 64)); } } /// @dev Calculate binary logarithm of x. Revert if x <= 0. /// @param x signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function log_2(int128 x) internal pure returns (int128) { unchecked { require(x > 0); int256 msb = 0; int256 xc = x; if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; } if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore int256 result = (msb - 64) << 64; uint256 ux = uint256(int256(x)) << uint256(127 - msb); for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) { ux *= ux; uint256 b = ux >> 255; ux >>= 127 + b; result += bit * int256(b); } return int128(result); } } /// @dev Calculate natural logarithm of x. Revert if x <= 0. /// @param x signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function ln(int128 x) internal pure returns (int128) { unchecked { require(x > 0); return int128(int256((uint256(int256(log_2(x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF) >> 128)); } } /// @dev Calculate binary exponent of x. Revert on overflow. /// @param x signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function exp_2(int128 x) internal pure returns (int128) { unchecked { require(x < 0x400000000000000000); // Overflow if (x < -0x400000000000000000) return 0; // Underflow uint256 result = 0x80000000000000000000000000000000; if (x & 0x8000000000000000 > 0) result = (result * 0x16A09E667F3BCC908B2FB1366EA957D3E) >> 128; if (x & 0x4000000000000000 > 0) result = (result * 0x1306FE0A31B7152DE8D5A46305C85EDEC) >> 128; if (x & 0x2000000000000000 > 0) result = (result * 0x1172B83C7D517ADCDF7C8C50EB14A791F) >> 128; if (x & 0x1000000000000000 > 0) result = (result * 0x10B5586CF9890F6298B92B71842A98363) >> 128; if (x & 0x800000000000000 > 0) result = (result * 0x1059B0D31585743AE7C548EB68CA417FD) >> 128; if (x & 0x400000000000000 > 0) result = (result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8) >> 128; if (x & 0x200000000000000 > 0) result = (result * 0x10163DA9FB33356D84A66AE336DCDFA3F) >> 128; if (x & 0x100000000000000 > 0) result = (result * 0x100B1AFA5ABCBED6129AB13EC11DC9543) >> 128; if (x & 0x80000000000000 > 0) result = (result * 0x10058C86DA1C09EA1FF19D294CF2F679B) >> 128; if (x & 0x40000000000000 > 0) result = (result * 0x1002C605E2E8CEC506D21BFC89A23A00F) >> 128; if (x & 0x20000000000000 > 0) result = (result * 0x100162F3904051FA128BCA9C55C31E5DF) >> 128; if (x & 0x10000000000000 > 0) result = (result * 0x1000B175EFFDC76BA38E31671CA939725) >> 128; if (x & 0x8000000000000 > 0) result = (result * 0x100058BA01FB9F96D6CACD4B180917C3D) >> 128; if (x & 0x4000000000000 > 0) result = (result * 0x10002C5CC37DA9491D0985C348C68E7B3) >> 128; if (x & 0x2000000000000 > 0) result = (result * 0x1000162E525EE054754457D5995292026) >> 128; if (x & 0x1000000000000 > 0) result = (result * 0x10000B17255775C040618BF4A4ADE83FC) >> 128; if (x & 0x800000000000 > 0) result = (result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB) >> 128; if (x & 0x400000000000 > 0) result = (result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9) >> 128; if (x & 0x200000000000 > 0) result = (result * 0x10000162E43F4F831060E02D839A9D16D) >> 128; if (x & 0x100000000000 > 0) result = (result * 0x100000B1721BCFC99D9F890EA06911763) >> 128; if (x & 0x80000000000 > 0) result = (result * 0x10000058B90CF1E6D97F9CA14DBCC1628) >> 128; if (x & 0x40000000000 > 0) result = (result * 0x1000002C5C863B73F016468F6BAC5CA2B) >> 128; if (x & 0x20000000000 > 0) result = (result * 0x100000162E430E5A18F6119E3C02282A5) >> 128; if (x & 0x10000000000 > 0) result = (result * 0x1000000B1721835514B86E6D96EFD1BFE) >> 128; if (x & 0x8000000000 > 0) result = (result * 0x100000058B90C0B48C6BE5DF846C5B2EF) >> 128; if (x & 0x4000000000 > 0) result = (result * 0x10000002C5C8601CC6B9E94213C72737A) >> 128; if (x & 0x2000000000 > 0) result = (result * 0x1000000162E42FFF037DF38AA2B219F06) >> 128; if (x & 0x1000000000 > 0) result = (result * 0x10000000B17217FBA9C739AA5819F44F9) >> 128; if (x & 0x800000000 > 0) result = (result * 0x1000000058B90BFCDEE5ACD3C1CEDC823) >> 128; if (x & 0x400000000 > 0) result = (result * 0x100000002C5C85FE31F35A6A30DA1BE50) >> 128; if (x & 0x200000000 > 0) result = (result * 0x10000000162E42FF0999CE3541B9FFFCF) >> 128; if (x & 0x100000000 > 0) result = (result * 0x100000000B17217F80F4EF5AADDA45554) >> 128; if (x & 0x80000000 > 0) result = (result * 0x10000000058B90BFBF8479BD5A81B51AD) >> 128; if (x & 0x40000000 > 0) result = (result * 0x1000000002C5C85FDF84BD62AE30A74CC) >> 128; if (x & 0x20000000 > 0) result = (result * 0x100000000162E42FEFB2FED257559BDAA) >> 128; if (x & 0x10000000 > 0) result = (result * 0x1000000000B17217F7D5A7716BBA4A9AE) >> 128; if (x & 0x8000000 > 0) result = (result * 0x100000000058B90BFBE9DDBAC5E109CCE) >> 128; if (x & 0x4000000 > 0) result = (result * 0x10000000002C5C85FDF4B15DE6F17EB0D) >> 128; if (x & 0x2000000 > 0) result = (result * 0x1000000000162E42FEFA494F1478FDE05) >> 128; if (x & 0x1000000 > 0) result = (result * 0x10000000000B17217F7D20CF927C8E94C) >> 128; if (x & 0x800000 > 0) result = (result * 0x1000000000058B90BFBE8F71CB4E4B33D) >> 128; if (x & 0x400000 > 0) result = (result * 0x100000000002C5C85FDF477B662B26945) >> 128; if (x & 0x200000 > 0) result = (result * 0x10000000000162E42FEFA3AE53369388C) >> 128; if (x & 0x100000 > 0) result = (result * 0x100000000000B17217F7D1D351A389D40) >> 128; if (x & 0x80000 > 0) result = (result * 0x10000000000058B90BFBE8E8B2D3D4EDE) >> 128; if (x & 0x40000 > 0) result = (result * 0x1000000000002C5C85FDF4741BEA6E77E) >> 128; if (x & 0x20000 > 0) result = (result * 0x100000000000162E42FEFA39FE95583C2) >> 128; if (x & 0x10000 > 0) result = (result * 0x1000000000000B17217F7D1CFB72B45E1) >> 128; if (x & 0x8000 > 0) result = (result * 0x100000000000058B90BFBE8E7CC35C3F0) >> 128; if (x & 0x4000 > 0) result = (result * 0x10000000000002C5C85FDF473E242EA38) >> 128; if (x & 0x2000 > 0) result = (result * 0x1000000000000162E42FEFA39F02B772C) >> 128; if (x & 0x1000 > 0) result = (result * 0x10000000000000B17217F7D1CF7D83C1A) >> 128; if (x & 0x800 > 0) result = (result * 0x1000000000000058B90BFBE8E7BDCBE2E) >> 128; if (x & 0x400 > 0) result = (result * 0x100000000000002C5C85FDF473DEA871F) >> 128; if (x & 0x200 > 0) result = (result * 0x10000000000000162E42FEFA39EF44D91) >> 128; if (x & 0x100 > 0) result = (result * 0x100000000000000B17217F7D1CF79E949) >> 128; if (x & 0x80 > 0) result = (result * 0x10000000000000058B90BFBE8E7BCE544) >> 128; if (x & 0x40 > 0) result = (result * 0x1000000000000002C5C85FDF473DE6ECA) >> 128; if (x & 0x20 > 0) result = (result * 0x100000000000000162E42FEFA39EF366F) >> 128; if (x & 0x10 > 0) result = (result * 0x1000000000000000B17217F7D1CF79AFA) >> 128; if (x & 0x8 > 0) result = (result * 0x100000000000000058B90BFBE8E7BCD6D) >> 128; if (x & 0x4 > 0) result = (result * 0x10000000000000002C5C85FDF473DE6B2) >> 128; if (x & 0x2 > 0) result = (result * 0x1000000000000000162E42FEFA39EF358) >> 128; if (x & 0x1 > 0) result = (result * 0x10000000000000000B17217F7D1CF79AB) >> 128; result >>= uint256(int256(63 - (x >> 64))); require(result <= uint256(int256(MAX_64x64))); return int128(int256(result)); } } /// @dev Calculate natural exponent of x. Revert on overflow. /// @param x signed 64.64-bit fixed point number /// @return signed 64.64-bit fixed point number function exp(int128 x) internal pure returns (int128) { unchecked { require(x < 0x400000000000000000); // Overflow if (x < -0x400000000000000000) return 0; // Underflow return exp_2(int128((int256(x) * 0x171547652B82FE1777D0FFDA0D23A7D12) >> 128)); } } /// @dev Calculate x / y rounding towards zero, where x and y are unsigned 256-bit /// integer numbers. Revert on overflow or when y is zero. /// @param x unsigned 256-bit integer number /// @param y unsigned 256-bit integer number /// @return unsigned 64.64-bit fixed point number function divuu(uint256 x, uint256 y) internal pure returns (uint128) { // ^^ changed visibility from private to internal for testing unchecked { require(y != 0); uint256 result; if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) result = (x << 64) / y; else { uint256 msb = 192; uint256 xc = x >> 192; if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore result = (x << (255 - msb)) / (((y - 1) >> (msb - 191)) + 1); require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); uint256 hi = result * (y >> 128); uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); uint256 xh = x >> 192; uint256 xl = x << 64; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here lo = hi << 128; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here assert(xh == hi >> 128); result += xl / y; } require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return uint128(result); } } /// @dev Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer number. /// @param x unsigned 256-bit integer number /// @return unsigned 128-bit integer number function sqrtu(uint256 x) internal pure returns (uint128) { // ^^ changed visibility from private to internal for testing unchecked { if (x == 0) return 0; else { uint256 xx = x; uint256 r = 1; if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; } if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; } if (xx >= 0x100000000) { xx >>= 32; r <<= 16; } if (xx >= 0x10000) { xx >>= 16; r <<= 8; } if (xx >= 0x100) { xx >>= 8; r <<= 4; } if (xx >= 0x10) { xx >>= 4; r <<= 2; } if (xx >= 0x8) { r <<= 1; } r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; // Seven iterations should be enough uint256 r1 = x / r; return uint128(r < r1 ? r : r1); } } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.15; /* __ ___ _ _ \ \ / (_) | | | | ██╗ ██╗██╗███████╗██╗ ██████╗ ███╗ ███╗ █████╗ ████████╗██╗ ██╗ \ \_/ / _ ___| | __| | ╚██╗ ██╔╝██║██╔════╝██║ ██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║ ██║ \ / | |/ _ \ |/ _` | ╚████╔╝ ██║█████╗ ██║ ██║ ██║██╔████╔██║███████║ ██║ ███████║ | | | | __/ | (_| | ╚██╔╝ ██║██╔══╝ ██║ ██║ ██║██║╚██╔╝██║██╔══██║ ██║ ██╔══██║ |_| |_|\___|_|\__,_| ██║ ██║███████╗███████╗██████╔╝██║ ╚═╝ ██║██║ ██║ ██║ ██║ ██║ yieldprotocol.com ╚═╝ ╚═╝╚══════╝╚══════╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ */ import {Exp64x64} from "./Exp64x64.sol"; import {Math64x64} from "./Math64x64.sol"; import {Cast} from "@yield-protocol/utils-v2/src/utils/Cast.sol"; /// Ethereum smart contract library implementing Yield Math model with yield bearing tokens. /// @dev see Mikhail Vladimirov (ABDK) explanations of the math: https://hackmd.io/gbnqA3gCTR6z-F0HHTxF-A#Yield-Math library YieldMath { using Math64x64 for int128; using Math64x64 for uint128; using Math64x64 for int256; using Math64x64 for uint256; using Exp64x64 for uint128; using Exp64x64 for int128; using Cast for uint256; using Cast for uint128; uint128 public constant WAD = 1e18; uint128 public constant ONE = 0x10000000000000000; // In 64.64 uint256 public constant MAX = type(uint128).max; // Used for overflow checks /* CORE FUNCTIONS ******************************************************************************************************************/ /* ---------------------------------------------------------------------------------------------------------------- ┌───────────────────────────────┐ .-:::::::::::-. ┌──────────────┐ │ │ .:::::::::::::::::. │$ $│ \│ │/ : _______ __ __ : │ ┌────────────┴─┐ \│ │/ :: | || | | |:: │ │$ $│ │ fyTokenOutForSharesIn │ ::: | ___|| |_| |::: │$│ ┌────────────┴─┐ ────────▶ │ │ ────────▶ ::: | |___ | |::: └─┤ │$ $│ │ │ ::: | ___||_ _|::: │$│ `sharesIn` │ /│ │\ ::: | | | | ::: └─┤ │ /│ │\ :: |___| |___| :: │$ $│ │ \(^o^)/ │ : ???? : └──────────────┘ │ YieldMath │ `:::::::::::::::::' └───────────────────────────────┘ `-:::::::::::-' */ /// Calculates the amount of fyToken a user would get for given amount of shares. /// https://docs.google.com/spreadsheets/d/14K_McZhlgSXQfi6nFGwDvDh4BmOu6_Hczi_sFreFfOE/ /// @param sharesReserves yield bearing vault shares reserve amount /// @param fyTokenReserves fyToken reserves amount /// @param sharesIn shares amount to be traded /// @param timeTillMaturity time till maturity in seconds e.g. 90 days in seconds /// @param k time till maturity coefficient, multiplied by 2^64. e.g. 25 years in seconds /// @param g fee coefficient, multiplied by 2^64 -- sb under 1.0 for selling shares to pool /// @param c price of shares in terms of their base, multiplied by 2^64 /// @param mu (μ) Normalization factor -- starts as c at initialization /// @return fyTokenOut the amount of fyToken a user would get for given amount of shares function fyTokenOutForSharesIn( uint128 sharesReserves, // z uint128 fyTokenReserves, // x uint128 sharesIn, // x == Δz uint128 timeTillMaturity, int128 k, int128 g, int128 c, int128 mu ) public pure returns (uint128) { unchecked { require(c > 0 && mu > 0, "YieldMath: c and mu must be positive"); uint128 a = _computeA(timeTillMaturity, k, g); uint256 sum; { /* https://docs.google.com/spreadsheets/d/14K_McZhlgSXQfi6nFGwDvDh4BmOu6_Hczi_sFreFfOE/ y = fyToken reserves z = shares reserves x = Δz (sharesIn) y - ( sum )^( invA ) y - (( Za ) + ( Ya ) - ( Zxa ) )^( invA ) Δy = y - ( c/μ * (μz)^(1-t) + y^(1-t) - c/μ * (μz + μx)^(1-t) )^(1 / (1 - t)) */ uint256 normalizedSharesReserves; require((normalizedSharesReserves = mu.mulu(sharesReserves)) <= MAX, "YieldMath: Rate overflow (nsr)"); // za = c/μ * (normalizedSharesReserves ** a) // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 za; require( (za = c.div(mu).mulu(uint128(normalizedSharesReserves).pow(a, ONE))) <= MAX, "YieldMath: Rate overflow (za)" ); // ya = fyTokenReserves ** a // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 ya = fyTokenReserves.pow(a, ONE); // normalizedSharesIn = μ * sharesIn uint256 normalizedSharesIn; require((normalizedSharesIn = mu.mulu(sharesIn)) <= MAX, "YieldMath: Rate overflow (nsi)"); // zx = normalizedSharesReserves + sharesIn * μ uint256 zx; require((zx = normalizedSharesReserves + normalizedSharesIn) <= MAX, "YieldMath: Too many shares in"); // zxa = c/μ * zx ** a // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 zxa; require((zxa = c.div(mu).mulu(uint128(zx).pow(a, ONE))) <= MAX, "YieldMath: Rate overflow (zxa)"); sum = za + ya - zxa; require(sum <= (za + ya), "YieldMath: Sum underflow"); } // result = fyTokenReserves - (sum ** (1/a)) // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 fyTokenOut; require( (fyTokenOut = uint256(fyTokenReserves) - sum.u128().pow(ONE, a)) <= MAX, "YieldMath: Rounding error" ); require(fyTokenOut <= fyTokenReserves, "YieldMath: > fyToken reserves"); return uint128(fyTokenOut); } } /* ---------------------------------------------------------------------------------------------------------------- .-:::::::::::-. ┌───────────────────────────────┐ .:::::::::::::::::. │ │ : _______ __ __ : \│ │/ ┌──────────────┐ :: | || | | |:: \│ │/ │$ $│ ::: | ___|| |_| |::: │ sharesOutForFYTokenIn │ │ ┌────────────┴─┐ ::: | |___ | |::: ────────▶ │ │ ────────▶ │ │$ $│ ::: | ___||_ _|::: │ │ │$│ ┌────────────┴─┐ ::: | | | | ::: /│ │\ └─┤ │$ $│ :: |___| |___| :: /│ │\ │$│ SHARES │ : `fyTokenIn` : │ \(^o^)/ │ └─┤ ???? │ `:::::::::::::::::' │ YieldMath │ │$ $│ `-:::::::::::-' └───────────────────────────────┘ └──────────────┘ */ /// Calculates the amount of shares a user would get for certain amount of fyToken. /// @param sharesReserves shares reserves amount /// @param fyTokenReserves fyToken reserves amount /// @param fyTokenIn fyToken amount to be traded /// @param timeTillMaturity time till maturity in seconds /// @param k time till maturity coefficient, multiplied by 2^64 /// @param g fee coefficient, multiplied by 2^64 /// @param c price of shares in terms of Dai, multiplied by 2^64 /// @param mu (μ) Normalization factor -- starts as c at initialization /// @return amount of Shares a user would get for given amount of fyToken function sharesOutForFYTokenIn( uint128 sharesReserves, uint128 fyTokenReserves, uint128 fyTokenIn, uint128 timeTillMaturity, int128 k, int128 g, int128 c, int128 mu ) public pure returns (uint128) { unchecked { require(c > 0 && mu > 0, "YieldMath: c and mu must be positive"); return _sharesOutForFYTokenIn( sharesReserves, fyTokenReserves, fyTokenIn, _computeA(timeTillMaturity, k, g), c, mu ); } } /// @dev Splitting sharesOutForFYTokenIn in two functions to avoid stack depth limits. function _sharesOutForFYTokenIn( uint128 sharesReserves, uint128 fyTokenReserves, uint128 fyTokenIn, uint128 a, int128 c, int128 mu ) private pure returns (uint128) { /* https://docs.google.com/spreadsheets/d/14K_McZhlgSXQfi6nFGwDvDh4BmOu6_Hczi_sFreFfOE/ y = fyToken reserves z = shares reserves x = Δy (fyTokenIn) z - ( rightTerm ) z - (invMu) * ( Za ) + ( Ya ) - ( Yxa ) / (c / μ) )^( invA ) Δz = z - 1/μ * ( ( (c / μ) * (μz)^(1-t) + y^(1-t) - (y + x)^(1-t) ) / (c / μ) )^(1 / (1 - t)) */ unchecked { // normalizedSharesReserves = μ * sharesReserves uint256 normalizedSharesReserves; require((normalizedSharesReserves = mu.mulu(sharesReserves)) <= MAX, "YieldMath: Rate overflow (nsr)"); uint128 rightTerm; { uint256 zaYaYxa; { // za = c/μ * (normalizedSharesReserves ** a) // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 za; require( (za = c.div(mu).mulu(uint128(normalizedSharesReserves).pow(a, ONE))) <= MAX, "YieldMath: Rate overflow (za)" ); // ya = fyTokenReserves ** a // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 ya = fyTokenReserves.pow(a, ONE); // yxa = (fyTokenReserves + x) ** a # x is aka Δy // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 yxa = (fyTokenReserves + fyTokenIn).pow(a, ONE); require((zaYaYxa = (za + ya - yxa)) <= MAX, "YieldMath: Rate overflow (yxa)"); } rightTerm = uint128( // Cast zaYaYxa/(c/μ).pow(1/a).div(μ) from int128 to uint128 - always positive int128( // Cast zaYaYxa/(c/μ).pow(1/a) from uint128 to int128 - always < zaYaYxa/(c/μ) uint128( // Cast zaYaYxa/(c/μ) from int128 to uint128 - always positive zaYaYxa.divu(uint128(c.div(mu))) // Cast c/μ from int128 to uint128 - always positive ).pow(uint128(ONE), a) // Cast 2^64 from int128 to uint128 - always positive ).div(mu) ); } require(rightTerm <= sharesReserves, "YieldMath: Rate underflow"); return sharesReserves - rightTerm; } } /* ---------------------------------------------------------------------------------------------------------------- .-:::::::::::-. ┌───────────────────────────────┐ .:::::::::::::::::. │ │ ┌──────────────┐ : _______ __ __ : \│ │/ │$ $│ :: | || | | |:: \│ │/ │ ┌────────────┴─┐ ::: | ___|| |_| |::: │ fyTokenInForSharesOut │ │ │$ $│ ::: | |___ | |::: ────────▶ │ │ ────────▶ │$│ ┌────────────┴─┐ ::: | ___||_ _|::: │ │ └─┤ │$ $│ ::: | | | | ::: /│ │\ │$│ │ :: |___| |___| :: /│ │\ └─┤ `sharesOut` │ : ???? : │ \(^o^)/ │ │$ $│ `:::::::::::::::::' │ YieldMath │ └──────────────┘ `-:::::::::::-' └───────────────────────────────┘ */ /// Calculates the amount of fyToken a user could sell for given amount of Shares. /// @param sharesReserves shares reserves amount /// @param fyTokenReserves fyToken reserves amount /// @param sharesOut Shares amount to be traded /// @param timeTillMaturity time till maturity in seconds /// @param k time till maturity coefficient, multiplied by 2^64 /// @param g fee coefficient, multiplied by 2^64 /// @param c price of shares in terms of Dai, multiplied by 2^64 /// @param mu (μ) Normalization factor -- starts as c at initialization /// @return fyTokenIn the amount of fyToken a user could sell for given amount of Shares function fyTokenInForSharesOut( uint128 sharesReserves, uint128 fyTokenReserves, uint128 sharesOut, uint128 timeTillMaturity, int128 k, int128 g, int128 c, int128 mu ) public pure returns (uint128) { /* https://docs.google.com/spreadsheets/d/14K_McZhlgSXQfi6nFGwDvDh4BmOu6_Hczi_sFreFfOE/ y = fyToken reserves z = shares reserves x = Δz (sharesOut) ( sum )^( invA ) - y ( Za ) + ( Ya ) - ( Zxa )^( invA ) - y Δy = ( c/μ * (μz)^(1-t) + y^(1-t) - c/μ * (μz - μx)^(1-t) )^(1 / (1 - t)) - y */ unchecked { require(c > 0 && mu > 0, "YieldMath: c and mu must be positive"); uint128 a = _computeA(timeTillMaturity, k, g); uint256 sum; { // normalizedSharesReserves = μ * sharesReserves uint256 normalizedSharesReserves; require((normalizedSharesReserves = mu.mulu(sharesReserves)) <= MAX, "YieldMath: Rate overflow (nsr)"); // za = c/μ * (normalizedSharesReserves ** a) // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 za; require( (za = c.div(mu).mulu(uint128(normalizedSharesReserves).pow(a, ONE))) <= MAX, "YieldMath: Rate overflow (za)" ); // ya = fyTokenReserves ** a // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 ya = fyTokenReserves.pow(a, ONE); // normalizedSharesOut = μ * sharesOut uint256 normalizedSharesOut; require((normalizedSharesOut = mu.mulu(sharesOut)) <= MAX, "YieldMath: Rate overflow (nso)"); // zx = normalizedSharesReserves + sharesOut * μ require(normalizedSharesReserves >= normalizedSharesOut, "YieldMath: Too many shares in"); uint256 zx = normalizedSharesReserves - normalizedSharesOut; // zxa = c/μ * zx ** a // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 zxa = c.div(mu).mulu(uint128(zx).pow(a, ONE)); // sum = za + ya - zxa // z < MAX, y < MAX, a < 1. It can only underflow, not overflow. require((sum = za + ya - zxa) <= MAX, "YieldMath: > fyToken reserves"); } // result = fyTokenReserves - (sum ** (1/a)) // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 result; require( (result = uint256(uint128(sum).pow(ONE, a)) - uint256(fyTokenReserves)) <= MAX, "YieldMath: Rounding error" ); return uint128(result); } } /* ---------------------------------------------------------------------------------------------------------------- ┌───────────────────────────────┐ .-:::::::::::-. ┌──────────────┐ │ │ .:::::::::::::::::. │$ $│ \│ │/ : _______ __ __ : │ ┌────────────┴─┐ \│ │/ :: | || | | |:: │ │$ $│ │ sharesInForFYTokenOut │ ::: | ___|| |_| |::: │$│ ┌────────────┴─┐ ────────▶ │ │ ────────▶ ::: | |___ | |::: └─┤ │$ $│ │ │ ::: | ___||_ _|::: │$│ SHARES │ /│ │\ ::: | | | | ::: └─┤ ???? │ /│ │\ :: |___| |___| :: │$ $│ │ \(^o^)/ │ : `fyTokenOut` : └──────────────┘ │ YieldMath │ `:::::::::::::::::' └───────────────────────────────┘ `-:::::::::::-' */ /// @param sharesReserves yield bearing vault shares reserve amount /// @param fyTokenReserves fyToken reserves amount /// @param fyTokenOut fyToken amount to be traded /// @param timeTillMaturity time till maturity in seconds e.g. 90 days in seconds /// @param k time till maturity coefficient, multiplied by 2^64. e.g. 25 years in seconds /// @param g fee coefficient, multiplied by 2^64 -- sb under 1.0 for selling shares to pool /// @param c price of shares in terms of their base, multiplied by 2^64 /// @param mu (μ) Normalization factor -- starts as c at initialization /// @return result the amount of shares a user would have to pay for given amount of fyToken function sharesInForFYTokenOut( uint128 sharesReserves, uint128 fyTokenReserves, uint128 fyTokenOut, uint128 timeTillMaturity, int128 k, int128 g, int128 c, int128 mu ) public pure returns (uint128) { unchecked { require(c > 0 && mu > 0, "YieldMath: c and mu must be positive"); return _sharesInForFYTokenOut( sharesReserves, fyTokenReserves, fyTokenOut, _computeA(timeTillMaturity, k, g), c, mu ); } } /// @dev Splitting sharesInForFYTokenOut in two functions to avoid stack depth limits function _sharesInForFYTokenOut( uint128 sharesReserves, uint128 fyTokenReserves, uint128 fyTokenOut, uint128 a, int128 c, int128 mu ) private pure returns (uint128) { /* https://docs.google.com/spreadsheets/d/14K_McZhlgSXQfi6nFGwDvDh4BmOu6_Hczi_sFreFfOE/ y = fyToken reserves z = shares reserves x = Δy (fyTokenOut) 1/μ * ( subtotal )^( invA ) - z 1/μ * (( Za ) + ( Ya ) - ( Yxa )) / (c/μ) )^( invA ) - z Δz = 1/μ * (( c/μ * μz^(1-t) + y^(1-t) - (y - x)^(1-t)) / (c/μ) )^(1 / (1 - t)) - z */ unchecked { // normalizedSharesReserves = μ * sharesReserves require(mu.mulu(sharesReserves) <= MAX, "YieldMath: Rate overflow (nsr)"); // za = c/μ * (normalizedSharesReserves ** a) // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 za = c.div(mu).mulu(uint128(mu.mulu(sharesReserves)).pow(a, ONE)); require(za <= MAX, "YieldMath: Rate overflow (za)"); // ya = fyTokenReserves ** a // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 ya = fyTokenReserves.pow(a, ONE); // yxa = (fyTokenReserves - x) ** aß // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 yxa = (fyTokenReserves - fyTokenOut).pow(a, ONE); require(fyTokenOut <= fyTokenReserves, "YieldMath: Underflow (yxa)"); uint256 zaYaYxa; require((zaYaYxa = (za + ya - yxa)) <= MAX, "YieldMath: Rate overflow (zyy)"); int128 subtotal = int128(ONE).div(mu).mul( (uint128(zaYaYxa.divu(uint128(c.div(mu)))).pow(uint128(ONE), uint128(a))).i128() ); // subtotal is calculated as a positive fraction multiplied by a uint so it cannot underflow when casting to uint and its ok to use a raw casting uint128 sharesOut = uint128(subtotal) - sharesReserves; require(sharesOut <= uint128(subtotal), "YieldMath: Underflow error"); return sharesOut; } } /// Calculates the max amount of fyToken a user could sell. /// @param sharesReserves yield bearing vault shares reserve amount /// @param fyTokenReserves fyToken reserves amount /// @param timeTillMaturity time till maturity in seconds e.g. 90 days in seconds /// @param k time till maturity coefficient, multiplied by 2^64. e.g. 25 years in seconds /// @param g fee coefficient, multiplied by 2^64 -- sb over 1.0 for buying shares from the pool /// @param c price of shares in terms of their base, multiplied by 2^64 /// @return fyTokenIn the max amount of fyToken a user could sell function maxFYTokenIn( uint128 sharesReserves, uint128 fyTokenReserves, uint128 timeTillMaturity, int128 k, int128 g, int128 c, int128 mu ) public pure returns (uint128 fyTokenIn) { /* https://docs.google.com/spreadsheets/d/14K_McZhlgSXQfi6nFGwDvDh4BmOu6_Hczi_sFreFfOE/ Y = fyToken reserves Z = shares reserves y = maxFYTokenIn ( sum )^( invA ) - Y ( Za ) + ( Ya ) )^( invA ) - Y Δy = ( c/μ * (μz)^(1-t) + Y^(1-t) )^(1 / (1 - t)) - Y */ unchecked { require(c > 0 && mu > 0, "YieldMath: c and mu must be positive"); uint128 a = _computeA(timeTillMaturity, k, g); uint256 sum; { // normalizedSharesReserves = μ * sharesReserves uint256 normalizedSharesReserves; require((normalizedSharesReserves = mu.mulu(sharesReserves)) <= MAX, "YieldMath: Rate overflow (nsr)"); // za = c/μ * (normalizedSharesReserves ** a) // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 za; require( (za = c.div(mu).mulu(uint128(normalizedSharesReserves).pow(a, ONE))) <= MAX, "YieldMath: Rate overflow (za)" ); // ya = fyTokenReserves ** a // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 ya = fyTokenReserves.pow(a, ONE); // sum = za + ya // z < MAX, y < MAX, a < 1. It can only underflow, not overflow. require((sum = za + ya) <= MAX, "YieldMath: > fyToken reserves"); } // result = (sum ** (1/a)) - fyTokenReserves // The “pow(x, y, z)” function not only calculates x^(y/z) but also normalizes the result to // fit into 64.64 fixed point number, i.e. it actually calculates: x^(y/z) * (2^63)^(1 - y/z) uint256 result; require( (result = uint256(uint128(sum).pow(ONE, a)) - uint256(fyTokenReserves)) <= MAX, "YieldMath: Rounding error" ); fyTokenIn = uint128(result); } } /// Calculates the max amount of fyToken a user could get. /// https://docs.google.com/spreadsheets/d/14K_McZhlgSXQfi6nFGwDvDh4BmOu6_Hczi_sFreFfOE/ /// @param sharesReserves yield bearing vault shares reserve amount /// @param fyTokenReserves fyToken reserves amount /// @param timeTillMaturity time till maturity in seconds e.g. 90 days in seconds /// @param k time till maturity coefficient, multiplied by 2^64. e.g. 25 years in seconds /// @param g fee coefficient, multiplied by 2^64 -- sb under 1.0 for selling shares to pool /// @param c price of shares in terms of their base, multiplied by 2^64 /// @param mu (μ) Normalization factor -- c at initialization /// @return fyTokenOut the max amount of fyToken a user could get function maxFYTokenOut( uint128 sharesReserves, uint128 fyTokenReserves, uint128 timeTillMaturity, int128 k, int128 g, int128 c, int128 mu ) public pure returns (uint128 fyTokenOut) { unchecked { require(c > 0 && mu > 0, "YieldMath: c and mu must be positive"); int128 a = int128(_computeA(timeTillMaturity, k, g)); /* y = maxFyTokenOut Y = fyTokenReserves (virtual) Z = sharesReserves Y - ( ( numerator ) / ( denominator ) )^invA Y - ( ( ( Za ) + ( Ya ) ) / ( denominator ) )^invA y = Y - ( ( c/μ * (μZ)^a + Y^a ) / ( c/μ + 1 ) )^(1/a) */ // za = c/μ * ((μ * (sharesReserves / 1e18)) ** a) int128 za = c.div(mu).mul(mu.mul(sharesReserves.divu(WAD)).pow(a)); // ya = (fyTokenReserves / 1e18) ** a int128 ya = fyTokenReserves.divu(WAD).pow(a); // numerator = za + ya int128 numerator = za.add(ya); // denominator = c/u + 1 int128 denominator = c.div(mu).add(int128(ONE)); // rightTerm = (numerator / denominator) ** (1/a) int128 rightTerm = numerator.div(denominator).pow(int128(ONE).div(a)); // maxFYTokenOut_ = fyTokenReserves - (rightTerm * 1e18) require((fyTokenOut = fyTokenReserves - uint128(rightTerm.mulu(WAD))) <= MAX, "YieldMath: Underflow error"); require(fyTokenOut <= fyTokenReserves, "YieldMath: Underflow error"); } } /// Calculates the max amount of base a user could sell. /// https://docs.google.com/spreadsheets/d/14K_McZhlgSXQfi6nFGwDvDh4BmOu6_Hczi_sFreFfOE/ /// @param sharesReserves yield bearing vault shares reserve amount /// @param fyTokenReserves fyToken reserves amount /// @param timeTillMaturity time till maturity in seconds e.g. 90 days in seconds /// @param k time till maturity coefficient, multiplied by 2^64. e.g. 25 years in seconds /// @param g fee coefficient, multiplied by 2^64 -- sb under 1.0 for selling shares to pool /// @param c price of shares in terms of their base, multiplied by 2^64 /// @param mu (μ) Normalization factor -- c at initialization /// @return sharesIn Calculates the max amount of base a user could sell. function maxSharesIn( uint128 sharesReserves, // z uint128 fyTokenReserves, // x uint128 timeTillMaturity, int128 k, int128 g, int128 c, int128 mu ) public pure returns (uint128 sharesIn) { unchecked { require(c > 0 && mu > 0, "YieldMath: c and mu must be positive"); int128 a = int128(_computeA(timeTillMaturity, k, g)); /* y = maxSharesIn_ Y = fyTokenReserves (virtual) Z = sharesReserves 1/μ ( ( numerator ) / ( denominator ) )^invA - Z 1/μ ( ( ( Za ) + ( Ya ) ) / ( denominator ) )^invA - Z y = 1/μ ( ( c/μ * (μZ)^a + Y^a ) / ( c/u + 1 ) )^(1/a) - Z */ // za = c/μ * ((μ * (sharesReserves / 1e18)) ** a) int128 za = c.div(mu).mul(mu.mul(sharesReserves.divu(WAD)).pow(a)); // ya = (fyTokenReserves / 1e18) ** a int128 ya = fyTokenReserves.divu(WAD).pow(a); // numerator = za + ya int128 numerator = za.add(ya); // denominator = c/u + 1 int128 denominator = c.div(mu).add(int128(ONE)); // leftTerm = 1/μ * (numerator / denominator) ** (1/a) int128 leftTerm = int128(ONE).div(mu).mul(numerator.div(denominator).pow(int128(ONE).div(a))); // maxSharesIn_ = (leftTerm * 1e18) - sharesReserves require((sharesIn = uint128(leftTerm.mulu(WAD)) - sharesReserves) <= MAX, "YieldMath: Underflow error"); require(sharesIn <= uint128(leftTerm.mulu(WAD)), "YieldMath: Underflow error"); } } /* This function is not needed as it's return value is driven directly by the shares liquidity of the pool https://hackmd.io/lRZ4mgdrRgOpxZQXqKYlFw?view#MaxSharesOut function maxSharesOut( uint128 sharesReserves, // z uint128 fyTokenReserves, // x uint128 timeTillMaturity, int128 k, int128 g, int128 c, int128 mu ) public pure returns (uint128 maxSharesOut_) {} */ /// Calculates the total supply invariant. /// https://docs.google.com/spreadsheets/d/14K_McZhlgSXQfi6nFGwDvDh4BmOu6_Hczi_sFreFfOE/ /// @param sharesReserves yield bearing vault shares reserve amount /// @param fyTokenReserves fyToken reserves amount /// @param totalSupply total supply /// @param timeTillMaturity time till maturity in seconds e.g. 90 days in seconds /// @param k time till maturity coefficient, multiplied by 2^64. e.g. 25 years in seconds /// @param g fee coefficient, multiplied by 2^64 -- use under 1.0 (g2) /// @param c price of shares in terms of their base, multiplied by 2^64 /// @param mu (μ) Normalization factor -- c at initialization /// @return result Calculates the total supply invariant. function invariant( uint128 sharesReserves, // z uint128 fyTokenReserves, // x uint256 totalSupply, // s uint128 timeTillMaturity, int128 k, int128 g, int128 c, int128 mu ) public pure returns (uint128 result) { if (totalSupply == 0) return 0; int128 a = int128(_computeA(timeTillMaturity, k, g)); result = _invariant(sharesReserves, fyTokenReserves, totalSupply, a, c, mu); } /// @param sharesReserves yield bearing vault shares reserve amount /// @param fyTokenReserves fyToken reserves amount /// @param totalSupply total supply /// @param a 1 - g * t computed /// @param c price of shares in terms of their base, multiplied by 2^64 /// @param mu (μ) Normalization factor -- c at initialization /// @return result Calculates the total supply invariant. function _invariant( uint128 sharesReserves, // z uint128 fyTokenReserves, // x uint256 totalSupply, // s int128 a, int128 c, int128 mu ) internal pure returns (uint128 result) { unchecked { require(c > 0 && mu > 0, "YieldMath: c and mu must be positive"); /* y = invariant Y = fyTokenReserves (virtual) Z = sharesReserves s = total supply c/μ ( ( numerator ) / ( denominator ) )^invA / s c/μ ( ( ( Za ) + ( Ya ) ) / ( denominator ) )^invA / s y = c/μ ( ( c/μ * (μZ)^a + Y^a ) / ( c/u + 1 ) )^(1/a) / s */ // za = c/μ * ((μ * (sharesReserves / 1e18)) ** a) int128 za = c.div(mu).mul(mu.mul(sharesReserves.divu(WAD)).pow(a)); // ya = (fyTokenReserves / 1e18) ** a int128 ya = fyTokenReserves.divu(WAD).pow(a); // numerator = za + ya int128 numerator = za.add(ya); // denominator = c/u + 1 int128 denominator = c.div(mu).add(int128(ONE)); // topTerm = c/μ * (numerator / denominator) ** (1/a) int128 topTerm = c.div(mu).mul((numerator.div(denominator)).pow(int128(ONE).div(a))); result = uint128((topTerm.mulu(WAD) * WAD) / totalSupply); } } /* UTILITY FUNCTIONS ******************************************************************************************************************/ function _computeA( uint128 timeTillMaturity, int128 k, int128 g ) private pure returns (uint128) { // t = k * timeTillMaturity int128 t = k.mul(timeTillMaturity.fromUInt()); require(t >= 0, "YieldMath: t must be positive"); // Meaning neither T or k can be negative // a = (1 - gt) int128 a = int128(ONE).sub(g.mul(t)); require(a > 0, "YieldMath: Too far from maturity"); require(a <= int128(ONE), "YieldMath: g must be positive"); return uint128(a); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. * * Roles are referred to by their `bytes4` identifier. These are expected to be the * signatures for all the functions in the contract. Special roles should be exposed * in the external API and be unique: * * ``` * bytes4 public constant ROOT = 0x00000000; * ``` * * Roles represent restricted access to a function call. For that purpose, use {auth}: * * ``` * function foo() public auth { * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `ROOT`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {setRoleAdmin}. * * WARNING: The `ROOT` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ contract AccessControl { struct RoleData { mapping (address => bool) members; bytes4 adminRole; } mapping (bytes4 => RoleData) private _roles; bytes4 public constant ROOT = 0x00000000; bytes4 public constant ROOT4146650865 = 0x00000000; // Collision protection for ROOT, test with ROOT12007226833() bytes4 public constant LOCK = 0xFFFFFFFF; // Used to disable further permissioning of a function bytes4 public constant LOCK8605463013 = 0xFFFFFFFF; // Collision protection for LOCK, test with LOCK10462387368() /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role * * `ROOT` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes4 indexed role, bytes4 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call. */ event RoleGranted(bytes4 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes4 indexed role, address indexed account, address indexed sender); /** * @dev Give msg.sender the ROOT role and create a LOCK role with itself as the admin role and no members. * Calling setRoleAdmin(msg.sig, LOCK) means no one can grant that msg.sig role anymore. */ constructor () { _grantRole(ROOT, msg.sender); // Grant ROOT to msg.sender _setRoleAdmin(LOCK, LOCK); // Create the LOCK role by setting itself as its own admin, creating an independent role tree } /** * @dev Each function in the contract has its own role, identified by their msg.sig signature. * ROOT can give and remove access to each function, lock any further access being granted to * a specific action, or even create other roles to delegate admin control over a function. */ modifier auth() { require (_hasRole(msg.sig, msg.sender), "Access denied"); _; } /** * @dev Allow only if the caller has been granted the admin role of `role`. */ modifier admin(bytes4 role) { require (_hasRole(_getRoleAdmin(role), msg.sender), "Only admin"); _; } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes4 role, address account) external view returns (bool) { return _hasRole(role, account); } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes4 role) external view returns (bytes4) { return _getRoleAdmin(role); } /** * @dev Sets `adminRole` as ``role``'s admin role. * If ``role``'s admin role is not `adminRole` emits a {RoleAdminChanged} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function setRoleAdmin(bytes4 role, bytes4 adminRole) external virtual admin(role) { _setRoleAdmin(role, adminRole); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes4 role, address account) external virtual admin(role) { _grantRole(role, account); } /** * @dev Grants all of `role` in `roles` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - For each `role` in `roles`, the caller must have ``role``'s admin role. */ function grantRoles(bytes4[] memory roles, address account) external virtual { for (uint256 i = 0; i < roles.length; i++) { require (_hasRole(_getRoleAdmin(roles[i]), msg.sender), "Only admin"); _grantRole(roles[i], account); } } /** * @dev Sets LOCK as ``role``'s admin role. LOCK has no members, so this disables admin management of ``role``. * Emits a {RoleAdminChanged} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function lockRole(bytes4 role) external virtual admin(role) { _setRoleAdmin(role, LOCK); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes4 role, address account) external virtual admin(role) { _revokeRole(role, account); } /** * @dev Revokes all of `role` in `roles` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - For each `role` in `roles`, the caller must have ``role``'s admin role. */ function revokeRoles(bytes4[] memory roles, address account) external virtual { for (uint256 i = 0; i < roles.length; i++) { require (_hasRole(_getRoleAdmin(roles[i]), msg.sender), "Only admin"); _revokeRole(roles[i], account); } } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes4 role, address account) external virtual { require(account == msg.sender, "Renounce only for self"); _revokeRole(role, account); } function _hasRole(bytes4 role, address account) internal view returns (bool) { return _roles[role].members[account]; } function _getRoleAdmin(bytes4 role) internal view returns (bytes4) { return _roles[role].adminRole; } function _setRoleAdmin(bytes4 role, bytes4 adminRole) internal virtual { if (_getRoleAdmin(role) != adminRole) { _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, adminRole); } } function _grantRole(bytes4 role, address account) internal { if (!_hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, msg.sender); } } function _revokeRole(bytes4 role, address account) internal { if (_hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, msg.sender); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.15; /* POOL EVENTS ******************************************************************************************************************/ abstract contract PoolEvents { /// Fees have been updated. event FeesSet(uint16 g1Fee); /// Pool is matured and all LP tokens burned. gg. event gg(); /// gm. Pool is initialized. event gm(); /// A liquidity event has occured (burn / mint). event Liquidity( uint32 maturity, address indexed from, address indexed to, address indexed fyTokenTo, int256 base, int256 fyTokens, int256 poolTokens ); /// The _update fn has run and cached balances updated. event Sync(uint112 baseCached, uint112 fyTokenCached, uint256 cumulativeBalancesRatio); /// One of the four trading functions has been called: /// - buyBase /// - sellBase /// - buyFYToken /// - sellFYToken event Trade(uint32 maturity, address indexed from, address indexed to, int256 base, int256 fyTokens); }
// SPDX-License-Identifier: MIT // Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/53516bc555a454862470e7860a9b5254db4d00f5/src/token/ERC20/ERC20Permit.sol pragma solidity ^0.8.0; import "./ERC20.sol"; import "./IERC2612.sol"; /** * @dev Extension of {ERC20} that allows token holders to use their tokens * without sending any transactions by setting {IERC20-allowance} with a * signature using the {permit} method, and then spend them via * {IERC20-transferFrom}. * * The {permit} signature mechanism conforms to the {IERC2612} interface. */ abstract contract ERC20Permit is ERC20, IERC2612 { mapping (address => uint256) public override nonces; bytes32 public immutable PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 private immutable _DOMAIN_SEPARATOR; uint256 public immutable deploymentChainId; constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_, decimals_) { deploymentChainId = block.chainid; _DOMAIN_SEPARATOR = _calculateDomainSeparator(block.chainid); } /// @dev Calculate the DOMAIN_SEPARATOR. function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256(bytes(version())), chainId, address(this) ) ); } /// @dev Return the DOMAIN_SEPARATOR. function DOMAIN_SEPARATOR() external view returns (bytes32) { return block.chainid == deploymentChainId ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(block.chainid); } /// @dev Setting the version as a function so that it can be overriden function version() public pure virtual returns(string memory) { return "1"; } /** * @dev See {IERC2612-permit}. * * In cases where the free option is not a concern, deadline can simply be * set to uint(-1), so it should be seen as an optional parameter */ function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external virtual override { require(deadline >= block.timestamp, "ERC20Permit: expired deadline"); bytes32 hashStruct = keccak256( abi.encode( PERMIT_TYPEHASH, owner, spender, amount, nonces[owner]++, deadline ) ); bytes32 hash = keccak256( abi.encodePacked( "\x19\x01", block.chainid == deploymentChainId ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(block.chainid), hashStruct ) ); address signer = ecrecover(hash, v, r, s); require( signer != address(0) && signer == owner, "ERC20Permit: invalid signature" ); _setAllowance(owner, spender, amount); } }
// SPDX-License-Identifier: MIT // Inspired on token.sol from DappHub. Natspec adpated from OpenZeppelin. pragma solidity ^0.8.0; import "./IERC20Metadata.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Calls to {transferFrom} do not check for allowance if the caller is the owner * of the funds. This allows to reduce the number of approvals that are necessary. * * Finally, {transferFrom} does not decrease the allowance if it is set to * type(uint256).max. This reduces the gas costs without any likely impact. */ contract ERC20 is IERC20Metadata { uint256 internal _totalSupply; mapping (address => uint256) internal _balanceOf; mapping (address => mapping (address => uint256)) internal _allowance; string public override name = "???"; string public override symbol = "???"; uint8 public override decimals = 18; /** * @dev Sets the values for {name}, {symbol} and {decimals}. */ constructor(string memory name_, string memory symbol_, uint8 decimals_) { name = name_; symbol = symbol_; decimals = decimals_; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() external view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address guy) external view virtual override returns (uint256) { return _balanceOf[guy]; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) external view virtual override returns (uint256) { return _allowance[owner][spender]; } /** * @dev See {IERC20-approve}. */ function approve(address spender, uint wad) external virtual override returns (bool) { return _setAllowance(msg.sender, spender, wad); } /** * @dev See {IERC20-transfer}. * * Requirements: * * - the caller must have a balance of at least `wad`. */ function transfer(address dst, uint wad) external virtual override returns (bool) { return _transfer(msg.sender, dst, wad); } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `src` must have a balance of at least `wad`. * - the caller is not `src`, it must have allowance for ``src``'s tokens of at least * `wad`. */ /// if_succeeds {:msg "TransferFrom - decrease allowance"} msg.sender != src ==> old(_allowance[src][msg.sender]) >= wad; function transferFrom(address src, address dst, uint wad) external virtual override returns (bool) { _decreaseAllowance(src, wad); return _transfer(src, dst, wad); } /** * @dev Moves tokens `wad` from `src` to `dst`. * * Emits a {Transfer} event. * * Requirements: * * - `src` must have a balance of at least `amount`. */ /// if_succeeds {:msg "Transfer - src decrease"} old(_balanceOf[src]) >= _balanceOf[src]; /// if_succeeds {:msg "Transfer - dst increase"} _balanceOf[dst] >= old(_balanceOf[dst]); /// if_succeeds {:msg "Transfer - supply"} old(_balanceOf[src]) + old(_balanceOf[dst]) == _balanceOf[src] + _balanceOf[dst]; function _transfer(address src, address dst, uint wad) internal virtual returns (bool) { require(_balanceOf[src] >= wad, "ERC20: Insufficient balance"); unchecked { _balanceOf[src] = _balanceOf[src] - wad; } _balanceOf[dst] = _balanceOf[dst] + wad; emit Transfer(src, dst, wad); return true; } /** * @dev Sets the allowance granted to `spender` by `owner`. * * Emits an {Approval} event indicating the updated allowance. */ function _setAllowance(address owner, address spender, uint wad) internal virtual returns (bool) { _allowance[owner][spender] = wad; emit Approval(owner, spender, wad); return true; } /** * @dev Decreases the allowance granted to the caller by `src`, unless src == msg.sender or _allowance[src][msg.sender] == MAX * * Emits an {Approval} event indicating the updated allowance, if the allowance is updated. * * Requirements: * * - `spender` must have allowance for the caller of at least * `wad`, unless src == msg.sender */ /// if_succeeds {:msg "Decrease allowance - underflow"} old(_allowance[src][msg.sender]) <= _allowance[src][msg.sender]; function _decreaseAllowance(address src, uint wad) internal virtual returns (bool) { if (src != msg.sender) { uint256 allowed = _allowance[src][msg.sender]; if (allowed != type(uint).max) { require(allowed >= wad, "ERC20: Insufficient approval"); unchecked { _setAllowance(src, msg.sender, allowed - wad); } } } return true; } /** @dev Creates `wad` tokens and assigns them to `dst`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. */ /// if_succeeds {:msg "Mint - balance overflow"} old(_balanceOf[dst]) >= _balanceOf[dst]; /// if_succeeds {:msg "Mint - supply overflow"} old(_totalSupply) >= _totalSupply; function _mint(address dst, uint wad) internal virtual returns (bool) { _balanceOf[dst] = _balanceOf[dst] + wad; _totalSupply = _totalSupply + wad; emit Transfer(address(0), dst, wad); return true; } /** * @dev Destroys `wad` tokens from `src`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `src` must have at least `wad` tokens. */ /// if_succeeds {:msg "Burn - balance underflow"} old(_balanceOf[src]) <= _balanceOf[src]; /// if_succeeds {:msg "Burn - supply underflow"} old(_totalSupply) <= _totalSupply; function _burn(address src, uint wad) internal virtual returns (bool) { unchecked { require(_balanceOf[src] >= wad, "ERC20: Insufficient balance"); _balanceOf[src] = _balanceOf[src] - wad; _totalSupply = _totalSupply - wad; emit Transfer(src, address(0), wad); } return true; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.15; /* POOL ERRORS ******************************************************************************************************************/ /// The pool has matured and maybe you should too. error AfterMaturity(); /// The approval of the sharesToken failed miserably. error ApproveFailed(); /// The update would cause the FYToken cached to be less than the total supply. This should never happen but may /// occur due to unexpected rounding errors. We cannot allow this to happen as it could have many unexpected and /// side effects which may pierce the fabric of the space-time continuum. error FYTokenCachedBadState(); /// The pool has already been initialized. What are you thinking? /// @dev To save gas, total supply == 0 is checked instead of a state variable. error Initialized(); /// Trade results in negative interest rates because fyToken balance < (newSharesBalance * mu). Don't neg me. error NegativeInterestRatesNotAllowed(uint128 newFYTokenBalance, uint128 newSharesBalanceTimesMu); /// Represents the fee in bps, and it cannot be larger than 10,000. /// @dev https://en.wikipedia.org/wiki/10,000 per wikipedia: /// 10,000 (ten thousand) is the natural number following 9,999 and preceding 10,001. /// @param proposedFee The fee that was proposed. error InvalidFee(uint16 proposedFee); /// The year is 2106 and an invalid maturity date was passed into the constructor. /// Maturity date must be less than type(uint32).max error MaturityOverflow(); /// Mu cannot be zero. And you're not a hero. error MuCannotBeZero(); /// Not enough base was found in the pool contract to complete the requested action. You just wasted gas. /// @param baseAvailable The amount of unaccounted for base tokens. /// @param baseNeeded The amount of base tokens required for the mint. error NotEnoughBaseIn(uint256 baseAvailable, uint256 baseNeeded); /// Not enough fYTokens were found in the pool contract to complete the requested action :( smh. /// @param fYTokensAvailable The amount of unaccounted for fYTokens. /// @param fYTokensNeeded The amount of fYToken tokens required for the mint. error NotEnoughFYTokenIn(uint256 fYTokensAvailable, uint256 fYTokensNeeded); /// The pool has not been initialized yet. INTRUDER ALERT! /// @dev To save gas, total supply == 0 is checked instead of a state variable error NotInitialized(); /// The reserves have changed compared with the last cache which causes the burn to fall outside the bounds of min/max /// slippage ratios selected. This is likely the result of a peanut butter sandwich attack. /// @param newRatio The ratio that would have resulted from the mint. /// @param minRatio The minimum ratio allowed as specified by the caller. /// @param maxRatio The maximum ratio allowed as specified by the caller error SlippageDuringBurn(uint256 newRatio, uint256 minRatio, uint256 maxRatio); /// The reserves have changed compared with the last cache which causes the mint to fall outside the bounds of min/max /// slippage ratios selected. This is likely the result of a bologna sandwich attack. /// @param newRatio The ratio that would have resulted from the mint. /// @param minRatio The minimum ratio allowed as specified by the caller. /// @param maxRatio The maximum ratio allowed as specified by the caller error SlippageDuringMint(uint256 newRatio, uint256 minRatio, uint256 maxRatio); /// Minimum amount of fyToken (per the min arg) would not be met for the trade. Try again. /// @param fyTokenOut fyTokens that would be obtained through the trade. /// @param min The minimum amount of fyTokens as specified by the caller. error SlippageDuringSellBase(uint128 fyTokenOut, uint128 min); /// Minimum amount of base (per the min arg) would not be met for the trade. Maybe you'll get lucky next time. /// @param baseOut bases that would be obtained through the trade. /// @param min The minimum amount of bases as specified by the caller. error SlippageDuringSellFYToken(uint128 baseOut, uint128 min);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.15; import "@yield-protocol/utils-v2/src/token/IERC20Metadata.sol"; import "@yield-protocol/utils-v2/src/token/IERC20.sol"; interface IERC4626 is IERC20, IERC20Metadata { function asset() external returns (IERC20); function convertToAssets(uint256 shares) external view returns (uint256); function convertToShares(uint256 assets) external view returns (uint256); function deposit(uint256 assets, address receiver) external returns (uint256 shares); function mint(address receiver, uint256 shares) external returns (uint256 assets); function previewDeposit(uint256 assets) external view returns (uint256 shares); function previewRedeem(uint256 shares) external view returns (uint256 assets); function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); }
// SPDX-License-Identifier: MIT // Taken from https://github.com/Uniswap/uniswap-lib/blob/master/src/libraries/TransferHelper.sol pragma solidity ^0.8.0; import "./IERC20.sol"; import "../utils/RevertMsgExtractor.sol"; // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false // USDT is a well known token that returns nothing for its transfer, transferFrom, and approve functions // and part of the reason this library exists library TransferHelper { /// @notice Transfers tokens from msg.sender to a recipient /// @dev Errors with the underlying revert message if transfer fails /// @param token The contract address of the token which will be transferred /// @param to The recipient of the transfer /// @param value The value of the transfer function safeTransfer( IERC20 token, address to, uint256 value ) internal { (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); if (!(success && _returnTrueOrNothing(data))) revert(RevertMsgExtractor.getRevertMsg(data)); } /// @notice Approves a spender to transfer tokens from msg.sender /// @dev Errors with the underlying revert message if transfer fails /// @param token The contract address of the token which will be approved /// @param spender The approved spender /// @param value The value of the allowance function safeApprove( IERC20 token, address spender, uint256 value ) internal { (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(IERC20.approve.selector, spender, value)); if (!(success && _returnTrueOrNothing(data))) revert(RevertMsgExtractor.getRevertMsg(data)); } /// @notice Transfers tokens from the targeted address to the given destination /// @dev Errors with the underlying revert message if transfer fails /// @param token The contract address of the token to be transferred /// @param from The originating address from which the tokens will be transferred /// @param to The destination address of the transfer /// @param value The amount to be transferred function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)); if (!(success && _returnTrueOrNothing(data))) revert(RevertMsgExtractor.getRevertMsg(data)); } /// @notice Transfers ETH to the recipient address /// @dev Errors with the underlying revert message if transfer fails /// @param to The destination of the transfer /// @param value The value to be transferred function safeTransferETH(address payable to, uint256 value) internal { (bool success, bytes memory data) = to.call{value: value}(new bytes(0)); if (!success) revert(RevertMsgExtractor.getRevertMsg(data)); } function _returnTrueOrNothing(bytes memory data) internal pure returns(bool) { return (data.length == 0 || abi.decode(data, (bool))); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.15; import "@yield-protocol/utils-v2/src/token/IERC20.sol"; interface IMaturingToken is IERC20 { function maturity() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.0; import "@yield-protocol/utils-v2/src/token/IERC20.sol"; import "@yield-protocol/utils-v2/src/token/IERC2612.sol"; import {IMaturingToken} from "./IMaturingToken.sol"; import {IERC20Metadata} from "@yield-protocol/utils-v2/src/token/ERC20.sol"; interface IPool is IERC20, IERC2612 { function baseToken() external view returns(IERC20Metadata); function base() external view returns(IERC20); function burn(address baseTo, address fyTokenTo, uint256 minRatio, uint256 maxRatio) external returns (uint256, uint256, uint256); function burnForBase(address to, uint256 minRatio, uint256 maxRatio) external returns (uint256, uint256); function buyBase(address to, uint128 baseOut, uint128 max) external returns(uint128); function buyBasePreview(uint128 baseOut) external view returns(uint128); function buyFYToken(address to, uint128 fyTokenOut, uint128 max) external returns(uint128); function buyFYTokenPreview(uint128 fyTokenOut) external view returns(uint128); function currentCumulativeRatio() external view returns (uint256 currentCumulativeRatio_, uint256 blockTimestampCurrent); function cumulativeRatioLast() external view returns (uint256); function fyToken() external view returns(IMaturingToken); function g1() external view returns(int128); function g2() external view returns(int128); function getC() external view returns (int128); function getCurrentSharePrice() external view returns (uint256); function getCache() external view returns (uint104 baseCached, uint104 fyTokenCached, uint32 blockTimestampLast, uint16 g1Fee_); function getBaseBalance() external view returns(uint128); function getFYTokenBalance() external view returns(uint128); function getSharesBalance() external view returns(uint128); function init(address to) external returns (uint256, uint256, uint256); function maturity() external view returns(uint32); function mint(address to, address remainder, uint256 minRatio, uint256 maxRatio) external returns (uint256, uint256, uint256); function mu() external view returns (int128); function mintWithBase(address to, address remainder, uint256 fyTokenToBuy, uint256 minRatio, uint256 maxRatio) external returns (uint256, uint256, uint256); function retrieveBase(address to) external returns(uint128 retrieved); function retrieveFYToken(address to) external returns(uint128 retrieved); function retrieveShares(address to) external returns(uint128 retrieved); function scaleFactor() external view returns(uint96); function sellBase(address to, uint128 min) external returns(uint128); function sellBasePreview(uint128 baseIn) external view returns(uint128); function sellFYToken(address to, uint128 min) external returns(uint128); function sellFYTokenPreview(uint128 fyTokenIn) external view returns(uint128); function setFees(uint16 g1Fee_) external; function sharesToken() external view returns(IERC20Metadata); function ts() external view returns(int128); function wrap(address receiver) external returns (uint256 shares); function wrapPreview(uint256 assets) external view returns (uint256 shares); function unwrap(address receiver) external returns (uint256 assets); function unwrapPreview(uint256 shares) external view returns (uint256 assets); /// Returns the max amount of FYTokens that can be sold to the pool function maxFYTokenIn() external view returns (uint128) ; /// Returns the max amount of FYTokens that can be bought from the pool function maxFYTokenOut() external view returns (uint128) ; /// Returns the max amount of Base that can be sold to the pool function maxBaseIn() external view returns (uint128) ; /// Returns the max amount of Base that can be bought from the pool function maxBaseOut() external view returns (uint128); /// Returns the result of the total supply invariant function function invariant() external view returns (uint128); }
// SPDX-License-Identifier: MIT // Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/ pragma solidity ^0.8.0; /** * @dev Interface of the ERC2612 standard as defined in the EIP. * * Adds the {permit} method, which can be used to change one's * {IERC20-allowance} without having to send a transaction, by signing a * message. This allows users to spend tokens without having to hold Ether. * * See https://eips.ethereum.org/EIPS/eip-2612. */ interface IERC2612 { /** * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens, * given `owner`'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; /** * @dev Returns the current ERC2612 nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); }
// SPDX-License-Identifier: MIT // Taken from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/src/token/ERC20/extensions/IERC20Metadata.sol pragma solidity ^0.8.0; import "./IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT // Taken from https://github.com/sushiswap/BoringSolidity/blob/441e51c0544cf2451e6116fe00515e71d7c42e2c/src/BoringBatchable.sol pragma solidity >=0.6.0; library RevertMsgExtractor { /// @dev Helper function to extract a useful revert message from a failed call. /// If the returned data is malformed or not correctly abi encoded then this call can fail itself. function getRevertMsg(bytes memory returnData) internal pure returns (string memory) { // If the _res length is less than 68, then the transaction failed silently (without a revert message) if (returnData.length < 68) return "Transaction reverted silently"; assembly { // Slice the sighash. returnData := add(returnData, 0x04) } return abi.decode(returnData, (string)); // All that remains is the revert string } }
{ "optimizer": { "enabled": true, "runs": 100 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "@yield-protocol/yieldspace-tv/src/YieldMath.sol": { "YieldMath": "0xe7a9771c692c428df17ecad6cd58d4938c010a2e" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"base_","type":"address"},{"internalType":"address","name":"fyToken_","type":"address"},{"internalType":"int128","name":"ts_","type":"int128"},{"internalType":"uint16","name":"g1Fee_","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AfterMaturity","type":"error"},{"inputs":[],"name":"FYTokenCachedBadState","type":"error"},{"inputs":[],"name":"Initialized","type":"error"},{"inputs":[{"internalType":"uint16","name":"proposedFee","type":"uint16"}],"name":"InvalidFee","type":"error"},{"inputs":[],"name":"MaturityOverflow","type":"error"},{"inputs":[],"name":"MuCannotBeZero","type":"error"},{"inputs":[{"internalType":"uint128","name":"newFYTokenBalance","type":"uint128"},{"internalType":"uint128","name":"newSharesBalanceTimesMu","type":"uint128"}],"name":"NegativeInterestRatesNotAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"baseAvailable","type":"uint256"},{"internalType":"uint256","name":"baseNeeded","type":"uint256"}],"name":"NotEnoughBaseIn","type":"error"},{"inputs":[{"internalType":"uint256","name":"fYTokensAvailable","type":"uint256"},{"internalType":"uint256","name":"fYTokensNeeded","type":"uint256"}],"name":"NotEnoughFYTokenIn","type":"error"},{"inputs":[],"name":"NotInitialized","type":"error"},{"inputs":[{"internalType":"uint256","name":"newRatio","type":"uint256"},{"internalType":"uint256","name":"minRatio","type":"uint256"},{"internalType":"uint256","name":"maxRatio","type":"uint256"}],"name":"SlippageDuringBurn","type":"error"},{"inputs":[{"internalType":"uint256","name":"newRatio","type":"uint256"},{"internalType":"uint256","name":"minRatio","type":"uint256"},{"internalType":"uint256","name":"maxRatio","type":"uint256"}],"name":"SlippageDuringMint","type":"error"},{"inputs":[{"internalType":"uint128","name":"fyTokenOut","type":"uint128"},{"internalType":"uint128","name":"min","type":"uint128"}],"name":"SlippageDuringSellBase","type":"error"},{"inputs":[{"internalType":"uint128","name":"baseOut","type":"uint128"},{"internalType":"uint128","name":"min","type":"uint128"}],"name":"SlippageDuringSellFYToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"g1Fee","type":"uint16"}],"name":"FeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"maturity","type":"uint32"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"fyTokenTo","type":"address"},{"indexed":false,"internalType":"int256","name":"base","type":"int256"},{"indexed":false,"internalType":"int256","name":"fyTokens","type":"int256"},{"indexed":false,"internalType":"int256","name":"poolTokens","type":"int256"}],"name":"Liquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"role","type":"bytes4"},{"indexed":true,"internalType":"bytes4","name":"newAdminRole","type":"bytes4"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"role","type":"bytes4"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"role","type":"bytes4"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint112","name":"baseCached","type":"uint112"},{"indexed":false,"internalType":"uint112","name":"fyTokenCached","type":"uint112"},{"indexed":false,"internalType":"uint256","name":"cumulativeBalancesRatio","type":"uint256"}],"name":"Sync","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"maturity","type":"uint32"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"int256","name":"base","type":"int256"},{"indexed":false,"internalType":"int256","name":"fyTokens","type":"int256"}],"name":"Trade","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[],"name":"gg","type":"event"},{"anonymous":false,"inputs":[],"name":"gm","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOCK","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOCK8605463013","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROOT","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROOT4146650865","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"base","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseTo","type":"address"},{"internalType":"address","name":"fyTokenTo","type":"address"},{"internalType":"uint256","name":"minRatio","type":"uint256"},{"internalType":"uint256","name":"maxRatio","type":"uint256"}],"name":"burn","outputs":[{"internalType":"uint256","name":"lpTokensBurned","type":"uint256"},{"internalType":"uint256","name":"baseOut","type":"uint256"},{"internalType":"uint256","name":"fyTokenOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minRatio","type":"uint256"},{"internalType":"uint256","name":"maxRatio","type":"uint256"}],"name":"burnForBase","outputs":[{"internalType":"uint256","name":"lpTokensBurned","type":"uint256"},{"internalType":"uint256","name":"baseOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint128","name":"baseOut","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"name":"buyBase","outputs":[{"internalType":"uint128","name":"fyTokenIn","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"baseOut","type":"uint128"}],"name":"buyBasePreview","outputs":[{"internalType":"uint128","name":"fyTokenIn","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint128","name":"fyTokenOut","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"name":"buyFYToken","outputs":[{"internalType":"uint128","name":"baseIn","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"fyTokenOut","type":"uint128"}],"name":"buyFYTokenPreview","outputs":[{"internalType":"uint128","name":"baseIn","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cumulativeRatioLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentCumulativeRatio","outputs":[{"internalType":"uint256","name":"currentCumulativeRatio_","type":"uint256"},{"internalType":"uint256","name":"blockTimestampCurrent","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deploymentChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fyToken","outputs":[{"internalType":"contract IMaturingToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"g1","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"g1Fee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"g2","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseBalance","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getC","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCache","outputs":[{"internalType":"uint104","name":"","type":"uint104"},{"internalType":"uint104","name":"","type":"uint104"},{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentSharePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFYTokenBalance","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSharesBalance","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4[]","name":"roles","type":"bytes4[]"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRoles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"init","outputs":[{"internalType":"uint256","name":"baseIn","type":"uint256"},{"internalType":"uint256","name":"fyTokenIn","type":"uint256"},{"internalType":"uint256","name":"lpTokensMinted","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"invariant","outputs":[{"internalType":"uint128","name":"result","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"}],"name":"lockRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maturity","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBaseIn","outputs":[{"internalType":"uint128","name":"baseIn","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBaseOut","outputs":[{"internalType":"uint128","name":"baseOut","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxFYTokenIn","outputs":[{"internalType":"uint128","name":"fyTokenIn","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxFYTokenOut","outputs":[{"internalType":"uint128","name":"fyTokenOut","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"remainder","type":"address"},{"internalType":"uint256","name":"minRatio","type":"uint256"},{"internalType":"uint256","name":"maxRatio","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"baseIn","type":"uint256"},{"internalType":"uint256","name":"fyTokenIn","type":"uint256"},{"internalType":"uint256","name":"lpTokensMinted","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"remainder","type":"address"},{"internalType":"uint256","name":"fyTokenToBuy","type":"uint256"},{"internalType":"uint256","name":"minRatio","type":"uint256"},{"internalType":"uint256","name":"maxRatio","type":"uint256"}],"name":"mintWithBase","outputs":[{"internalType":"uint256","name":"baseIn","type":"uint256"},{"internalType":"uint256","name":"fyTokenIn","type":"uint256"},{"internalType":"uint256","name":"lpTokensMinted","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mu","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"retrieveBase","outputs":[{"internalType":"uint128","name":"retrieved","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"retrieveFYToken","outputs":[{"internalType":"uint128","name":"retrieved","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"retrieveShares","outputs":[{"internalType":"uint128","name":"retrieved","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4[]","name":"roles","type":"bytes4[]"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRoles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"scaleFactor","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint128","name":"min","type":"uint128"}],"name":"sellBase","outputs":[{"internalType":"uint128","name":"fyTokenOut","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"baseIn","type":"uint128"}],"name":"sellBasePreview","outputs":[{"internalType":"uint128","name":"fyTokenOut","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint128","name":"min","type":"uint128"}],"name":"sellFYToken","outputs":[{"internalType":"uint128","name":"baseOut","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"fyTokenIn","type":"uint128"}],"name":"sellFYTokenPreview","outputs":[{"internalType":"uint128","name":"baseOut","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"g1Fee_","type":"uint16"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"},{"internalType":"bytes4","name":"adminRole","type":"bytes4"}],"name":"setRoleAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sharesToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ts","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"unwrap","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"unwrapPreview","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"wrap","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"wrapPreview","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"}]
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103d95760003560e01c80639a7dac2811610206578063c03edd221161012b578063dc3bfba9116100c3578063effae35311610087578063effae35314610a39578063fa296879146107b2578063fdb0732d14610a4c578063fe2846b114610a5f578063ffffffff146107f057600080fd5b8063dc3bfba914610997578063dd363371146109be578063dd62ed3e146109c6578063de02cde7146109ff578063e86d60bf14610a1257600080fd5b8063c03edd22146108ed578063c200ac87146108f5578063c55dae63146108fd578063c849817114610797578063ca1123c214610924578063cd0d009614610937578063d3d00f241461095e578063d505accf14610971578063d7020d0a1461098457600080fd5b8063ae93c1b51161019e578063ae93c1b514610855578063b03a9a0514610868578063b0f2892114610870578063b3f1c93d14610883578063b76dab6214610896578063bc24e2491461089e578063bc3d1c4e146108bf578063bcc1694f146108d2578063bdd8a366146108e557600080fd5b80639a7dac28146107c55780639ebdc9b4146107cd578063a2375d1e146107e0578063a39ce8c0146107e8578063a4f0d7d0146107f0578063a694dc19146107ff578063a9059cbb14610808578063ab4f97181461081b578063ad82110f1461084257600080fd5b80633644e51511610307578063683dd1911161029f5780637ecebe00116102635780637ecebe00146107505780638009ba1f146107705780638e95d1801461079757806395d89b41146107aa57806396d3f339146107b257600080fd5b8063683dd191146106ba578063687f0e4c146106f95780636970a9241461070c57806370a082311461072757806375f26e631461041a57600080fd5b80633644e515146106305780633d6d9d011461063857806344faded0146106405780635001f3b51461065557806354fd4d5014610684578063559742d91461068c5780635909c12f146103de5780635ba5e9f01461069f5780635f238702146106b257600080fd5b806319ab453c1161037a57806319ab453c146104f85780631eb728fc14610526578063204f83f914610539578063210a49911461057557806323b872dd1461059d57806327bab063146105b057806330adf81f146105c3578063313ce567146105ea57806333f761781461060957600080fd5b80156103de57806302236e8914610404578063023276f01461041a57806306fdde031461042d578063095ea7b3146104425780630a0d86861461046557806310ab9432146104b257806313e7bc8c146104c557806318160ddd146104f0575b600080fd5b6103e6600081565b6040516001600160e01b031990911681526020015b60405180910390f35b61040c610a72565b6040519081526020016103fb565b61040c6104283660046141df565b610a81565b610435610a92565b6040516103fb9190614226565b610455610450366004614259565b610b20565b60405190151581526020016103fb565b600854604080516001600160681b0362010000840481168252600160781b840416602082015263ffffffff600160e01b8404169181019190915261ffff90911660608201526080016103fb565b6104556104c036600461429b565b610b34565b6104d86104d33660046142e6565b610b40565b6040516001600160801b0390911681526020016103fb565b60005461040c565b61050b6105063660046141df565b610b81565b604080519384526020840192909252908201526060016103fb565b61050b610534366004614303565b610c2a565b6105607f000000000000000000000000000000000000000000000000000000006516e67081565b60405163ffffffff90911681526020016103fb565b610588610583366004614350565b610c6f565b604080519283526020830191909152016103fb565b6104556105ab366004614383565b610cd4565b6104d86105be3660046142e6565b610cf4565b61040c7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b6005546105f79060ff1681565b60405160ff90911681526020016103fb565b61040c7f000000000000000000000000000000000000000000000000000000000000001281565b61040c610d37565b6104d8610d8e565b61065361064e36600461429b565b610da6565b005b7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f5b6040516103fb91906143bf565b610435610de4565b61065361069a3660046143d3565b610dff565b6103e66106ad3660046143d3565b610e3e565b6104d8610e49565b6106e17f000000000000000000000000000000000000000000000000000000000000000181565b6040516001600160601b0390911681526020016103fb565b61065361070736600461429b565b610fc1565b61071461101c565b604051600f9190910b81526020016103fb565b61040c6107353660046141df565b6001600160a01b031660009081526001602052604090205490565b61040c61075e3660046141df565b60066020526000908152604090205481565b6106777f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f81565b61040c6107a53660046143ee565b61103c565b610435611044565b6104d86107c03660046141df565b611051565b61058861105c565b6104d86107db366004614407565b6110c8565b61071461125f565b6104d8611269565b6103e66001600160e01b031981565b61040c60095481565b610455610816366004614259565b611345565b6107147f000000000000000000000000000000000000000000000001000000000000000081565b610653610850366004614497565b611352565b610653610863366004614556565b6113d4565b6104d8611407565b6104d861087e3660046142e6565b611590565b61050b610891366004614580565b6115c7565b6104d861160c565b6008546108ac9061ffff1681565b60405161ffff90911681526020016103fb565b6104d86108cd3660046145c2565b6117b9565b6104d86108e03660046145c2565b611911565b610714611af5565b6104d8611b0f565b6104d8611b19565b6106777f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f81565b6106536109323660046145f9565b611b3c565b61040c7f000000000000000000000000000000000000000000000000000000000000000181565b6104d861096c3660046141df565b611be5565b61065361097f36600461461d565b611c51565b61050b610992366004614580565b611ec0565b6106777f000000000000000000000000b917a6cd3f811a84c1c5b972e2c715a6d93f40aa81565b6104d8611ed3565b61040c6109d4366004614690565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b610653610a0d36600461429b565b611ee0565b6107147f000000000000000000000000000000000000000000000000000000030640f90e81565b610653610a47366004614497565b611f13565b6104d8610a5a3660046142e6565b611f88565b6104d8610a6d366004614407565b611fc9565b6000610a7c612219565b905090565b6000610a8c82612246565b92915050565b60038054610a9f906146ac565b80601f0160208091040260200160405190810160405280929190818152602001828054610acb906146ac565b8015610b185780601f10610aed57610100808354040283529160200191610b18565b820191906000526020600020905b815481529060010190602001808311610afb57829003601f168201915b505050505081565b6000610b2d3384846122bc565b9392505050565b6000610b2d8383612325565b600080610b4b61235c565b9050610b2d610b676001600160801b0385166123d0565b6123d0565b602083015160408401518451610b7c906123fd565b61240f565b6000806000610b9c6000356001600160e01b03191633612325565b610bc15760405162461bcd60e51b8152600401610bb8906146e6565b60405180910390fd5b60005415610be2576040516302ed543d60e51b815260040160405180910390fd5b610bf28430600080600019612641565b60405192955090935091507fc0129d43587735024205b754136984ddcbe8c50e115c5dbaf8808163973e6a2f90600090a19193909250565b60008060008054600003610c51576040516321c4e35760e21b815260040160405180910390fd5b610c5e8888888888612641565b919a90995090975095505050505050565b6000807f000000000000000000000000000000000000000000000000000000006516e67063ffffffff164210610cb8576040516304ff30ef60e21b815260040160405180910390fd5b610cc785600060018787612bc7565b5090969095509350505050565b6000610ce0848361309c565b50610cec848484613145565b949350505050565b600080610cff61235c565b90506000610d238483602001518460400151610d1e86600001516131f2565b613204565b9050610cec6001600160801b0382166123d0565b60007f00000000000000000000000000000000000000000000000000000000000000014614610d6957610a7c466133ae565b507f214f32b97c88b0791e52e0ffc1cd6f14ab3caf7c1114fdbf6cacb76bb9b4c3cf90565b6000610d9861343f565b6001600160681b0316905090565b81610db9610db3826134d6565b33612325565b610dd55760405162461bcd60e51b8152600401610bb89061470d565b610ddf83836134f8565b505050565b6040805180820190915260018152603160f81b602082015290565b80610e0c610db3826134d6565b610e285760405162461bcd60e51b8152600401610bb89061470d565b610e3a826001600160e01b0319613569565b5050565b6000610a8c826134d6565b60007f000000000000000000000000000000000000000000000000000000000000000181610e7561235c565b9050816001600160601b031673e7a9771c692c428df17ecad6cd58d4938c010a2e6252c4f2846001600160601b03168460200151610eb39190614747565b856001600160601b03168560400151610ecc9190614747565b610ef6427f000000000000000000000000000000000000000000000000000000006516e670614776565b7f000000000000000000000000000000000000000000000000000000030640f90e610f2488600001516131f2565b610f2c6135e8565b7f00000000000000000000000000000000000000000000000100000000000000006040518863ffffffff1660e01b8152600401610f6f979695949392919061479b565b602060405180830381865af4158015610f8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb091906147e7565b610fba919061481a565b9250505090565b6001600160a01b03811633146110125760405162461bcd60e51b81526020600482015260166024820152752932b737bab731b29037b7363c903337b91039b2b63360511b6044820152606401610bb8565b610e3a82826134f8565b60008061102761235c565b905061103681600001516131f2565b91505090565b600081610a8c565b60048054610a9f906146ac565b6000610a8c82613638565b6008546000904290600160e01b810463ffffffff168203906110b490611090906201000090046001600160681b031661371f565b6008546110ae908490600160781b90046001600160681b0316614840565b9061374e565b6009546110c1919061485f565b9250509091565b6000806110d3613771565b6001600160681b0316905060006110e861235c565b905060006110fe6001600160801b0387166123d0565b9050611120818360200151846040015161111b86600001516131f2565b613810565b9350836001600160801b031682604001516001600160681b0316846111459190614877565b6001600160801b0316101561118857604082015161116c906001600160681b031684614877565b84604051638d8239e960e01b8152600401610bb8929190614897565b6111cc8183602001516001600160681b03166111a49190614877565b8584604001516001600160681b03166111bd91906148b1565b846020015185604001516138a7565b6111d587612246565b506001600160a01b03871633600080516020614d808339815191527f000000000000000000000000000000000000000000000000000000006516e6706112236001600160801b038b16613a51565b611235896001600160801b0316613a51565b61123e906148dc565b60405161124d939291906148ff565b60405180910390a35050509392505050565b6000610a7c6135e8565b60007f00000000000000000000000000000000000000000000000000000000000000018161129561235c565b9050816001600160601b031673e7a9771c692c428df17ecad6cd58d4938c010a2e6328cfa369846001600160601b031684602001516112d49190614747565b856001600160601b031685604001516112ed9190614747565b611317427f000000000000000000000000000000000000000000000000000000006516e670614776565b7f000000000000000000000000000000000000000000000000000000030640f90e610f2488600001516123fd565b6000610b2d338484613145565b60005b8251811015610ddf57611383610db384838151811061137657611376614921565b60200260200101516134d6565b61139f5760405162461bcd60e51b8152600401610bb89061470d565b6113c28382815181106113b4576113b4614921565b6020026020010151836134f8565b806113cc81614937565b915050611355565b816113e1610db3826134d6565b6113fd5760405162461bcd60e51b8152600401610bb89061470d565b610ddf8383613569565b60007f00000000000000000000000000000000000000000000000000000000000000018161143361235c565b9050816001600160601b031673e7a9771c692c428df17ecad6cd58d4938c010a2e63bda6a2b5846001600160601b031684602001516114729190614747565b856001600160601b0316856040015161148b9190614747565b866001600160601b03166000546114a29190614840565b6114cc427f000000000000000000000000000000000000000000000000000000006516e670614776565b7f000000000000000000000000000000000000000000000000000000030640f90e6114fa89600001516131f2565b6115026135e8565b6040516001600160e01b031960e08a901b1681526001600160681b039788166004820152969095166024870152604486019390935263ffffffff919091166064850152600f90810b608485015290810b60a484015290810b60c48301527f0000000000000000000000000000000000000000000000010000000000000000900b60e482015261010401610f6f565b60008061159b61235c565b9050610b2d6115b26001600160801b0385166123d0565b60208301516040840151845161111b906131f2565b600080600080546000036115ee576040516321c4e35760e21b815260040160405180910390fd5b6115fc878760008888612641565b9199909850909650945050505050565b60007f00000000000000000000000000000000000000000000000000000000000000018161163861235c565b90506000826001600160601b03166305f5e10073e7a9771c692c428df17ecad6cd58d4938c010a2e635e6ad856866001600160601b0316866020015161167e9190614747565b876001600160601b031687604001516116979190614747565b6116c1427f000000000000000000000000000000000000000000000000000000006516e670614776565b7f000000000000000000000000000000000000000000000000000000030640f90e6116ef8a600001516123fd565b6116f76135e8565b7f00000000000000000000000000000000000000000000000100000000000000006040518863ffffffff1660e01b815260040161173a979695949392919061479b565b602060405180830381865af4158015611757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177b91906147e7565b611785919061481a565b611793906305f5e100614950565b61179d919061481a565b90506117b16001600160801b0382166123d0565b935050505090565b6000806117c461235c565b905060006117d0613771565b905060008260400151826117e49190614976565b6001600160681b03169050600061180c8285602001518660400151610d1e88600001516131f2565b90506118438185602001516001600160681b031661182a9190614877565b846001600160681b0316866020015187604001516138a7565b61184f610b6288612246565b9450856001600160801b0316856001600160801b0316101561188857848660405163644a0abd60e01b8152600401610bb8929190614897565b6001600160a01b03871633600080516020614d808339815191527f000000000000000000000000000000000000000000000000000000006516e6706118d56001600160801b038a16613a51565b6118e7876001600160801b0316613a51565b6118f0906148dc565b6040516118ff939291906148ff565b60405180910390a35050505092915050565b600061191c30612246565b50600061192761235c565b9050600061193361343f565b905060008260200151826119479190614976565b6001600160681b0316905061196d8184602001518560400151610b7c87600001516123fd565b9350846001600160801b0316846001600160801b031610156119a6578385604051634178a7a160e11b8152600401610bb8929190614897565b6119db826001600160681b03168585604001516001600160681b03166119cc9190614877565b856020015186604001516138a7565b611a186001600160a01b037f000000000000000000000000b917a6cd3f811a84c1c5b972e2c715a6d93f40aa16876001600160801b038716613a7a565b6000548484604001516001600160681b0316611a349190614877565b6001600160801b03161015611a5c5760405163efd61adb60e01b815260040160405180910390fd5b6001600160a01b03861633600080516020614d808339815191527f000000000000000000000000000000000000000000000000000000006516e670611aba611aac6001600160801b0387166123d0565b6001600160801b0316613a51565b611ac3906148dc565b611ad5896001600160801b0316613a51565b604051611ae4939291906148ff565b60405180910390a350505092915050565b600080611b0061235c565b905061103681600001516123fd565b6000610d98613771565b600080611b2461235c565b602001516001600160681b03169050611036816123d0565b611b526000356001600160e01b03191633612325565b611b6e5760405162461bcd60e51b8152600401610bb8906146e6565b6127108161ffff161115611b9b5760405163f6f4a38f60e01b815261ffff82166004820152602401610bb8565b6008805461ffff191661ffff83169081179091556040519081527f51632c70eb300357eeb084d66c71fab660ab452e9be56eb1390ece79f8aa06e29060200160405180910390a150565b600854600090600160781b90046001600160681b0316611c03613771565b611c0d9190614976565b6001600160681b03169050611c4c6001600160a01b037f000000000000000000000000b917a6cd3f811a84c1c5b972e2c715a6d93f40aa168383613a7a565b919050565b42841015611ca15760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610bb8565b6001600160a01b038716600090815260066020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918a918a918a919086611cee83614937565b909155506040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e00160405160208183030381529060405280519060200120905060007f00000000000000000000000000000000000000000000000000000000000000014614611d7957611d74466133ae565b611d9b565b7f214f32b97c88b0791e52e0ffc1cd6f14ab3caf7c1114fdbf6cacb76bb9b4c3cf5b60405161190160f01b602082015260228101919091526042810183905260620160408051601f198184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015611e26573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590611e5c5750896001600160a01b0316816001600160a01b0316145b611ea85760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610bb8565b611eb38a8a8a6122bc565b5050505050505050505050565b60008060006115fc878760008888612bc7565b6000610a7c610b62613b5b565b81611eed610db3826134d6565b611f095760405162461bcd60e51b8152600401610bb89061470d565b610ddf8383613bb5565b60005b8251811015610ddf57611f37610db384838151811061137657611376614921565b611f535760405162461bcd60e51b8152600401610bb89061470d565b611f76838281518110611f6857611f68614921565b602002602001015183613bb5565b80611f8081614937565b915050611f16565b600080611f9361235c565b90506000610d238483602001516001600160681b031684604001516001600160681b0316611fc486600001516123fd565b613c28565b6000611fd430612246565b506000611fdf61343f565b6001600160681b031690506000611ff461235c565b905060006120258683602001516001600160681b031684604001516001600160681b0316611fc486600001516123fd565b90506120396001600160801b0382166123d0565b9350806001600160801b031682602001516001600160681b03168461205e9190614877565b6001600160801b031610156120c15761209582602001516001600160681b0316846120899190614877565b6001600160801b031690565b604051636874461960e01b815260048101919091526001600160801b0385166024820152604401610bb8565b6120f68183602001516001600160681b03166120dd91906148b1565b8784604001516001600160681b03166111bd9190614877565b6121336001600160a01b037f000000000000000000000000b917a6cd3f811a84c1c5b972e2c715a6d93f40aa16886001600160801b038916613a7a565b6000548683604001516001600160681b031661214f9190614877565b6001600160801b031610156121775760405163efd61adb60e01b815260040160405180910390fd5b6001600160a01b03871633600080516020614d808339815191527f000000000000000000000000000000000000000000000000000000006516e6706121c46001600160801b038916613a51565b6121cd906148dc565b61123e8b6001600160801b0316613a51565b6000816000036121ee57600080fd5b60006121fa8484613e0b565b905060016001607f1b036001600160801b0382161115610b2d57600080fd5b6000610a7c7f0000000000000000000000000000000000000000000000000000000000000012600a614a7a565b6008546000906201000090046001600160681b031661226361343f565b61226d9190614976565b6001600160681b031690506001600160a01b0382163014611c4c57611c4c6001600160a01b037f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f168383613a7a565b6001600160a01b03838116600081815260026020908152604080832094871680845294825280832086905551858152919392917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a35060019392505050565b6001600160e01b0319821660009081526007602090815260408083206001600160a01b038516845290915290205460ff1692915050565b604080516080810182526000808252602082018190529181018290526060810191909152506040805160808101825260085461ffff811682526201000081046001600160681b039081166020840152600160781b82041692820192909252600160e01b90910463ffffffff16606082015290565b60006001600160801b038211156123f95760405162461bcd60e51b8152600401610bb890614a86565b5090565b6000610a8c61ffff83166127106121df565b60007f000000000000000000000000000000000000000000000000000000006516e67063ffffffff164210612457576040516304ff30ef60e21b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000016001600160601b03811673e7a9771c692c428df17ecad6cd58d4938c010a2e63dd46e4ae6124a68389614747565b6124b96001600160601b03861689614747565b6124cc6001600160601b0387168c614950565b6124f6427f000000000000000000000000000000000000000000000000000000006516e670614776565b7f000000000000000000000000000000000000000000000000000000030640f90e8a6125206135e8565b7f00000000000000000000000000000000000000000000000100000000000000006040518963ffffffff1660e01b8152600401612564989796959493929190614aad565b602060405180830381865af4158015612581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a591906147e7565b6125af919061481a565b915060006125da610b626125cc896001600160681b038a166148b1565b6001600160801b031661371f565b90506001600160801b0381166125f9846001600160681b038816614877565b6001600160801b031610156126375761261b836001600160681b038716614877565b8160405163b24d9e1b60e01b8152600401610bb8929190614897565b5050949350505050565b60008060007f000000000000000000000000000000000000000000000000000000006516e67063ffffffff16421061268c576040516304ff30ef60e21b815260040160405180910390fd5b6040516370a0823160e01b81526001600160a01b037f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f16906370a08231906126d89030906004016143bf565b602060405180830381865afa1580156126f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127199190614b0c565b925061272430612246565b50600080549061273261235c565b905060008282604001516001600160681b031661274f9190614b25565b9050600061275b61343f565b6001600160681b0316905081156127f65760208301518990612786906001600160681b031684613f70565b10806127a95750602083015188906127a7906001600160681b031684613f70565b115b156127f15760208301516127c6906001600160681b031683613f70565b60405163d48b6b8160e01b81526004810191909152602481018a905260448101899052606401610bb8565b61282b565b60001988101561282b5760405163d48b6b8160e01b81526000196004820152602481018a905260448101899052606401610bb8565b6000846000036128475750806128408161371f565b9550612a39565b8260000361288c576020840151612867906001600160681b031683614b25565b60208501519091506001600160681b03166128828287614840565b6128409190614b3c565b60008b156128d5576128c96128a08d6123d0565b86602001516001600160681b031687604001516001600160681b0316611fc489600001516123fd565b6001600160801b031690505b6040516370a0823160e01b815284906001600160a01b037f000000000000000000000000b917a6cd3f811a84c1c5b972e2c715a6d93f40aa16906370a08231906129239030906004016143bf565b602060405180830381865afa158015612940573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129649190614b0c565b61296e9190614b25565b975061297a8c85614b25565b612984898e61485f565b61298e9088614840565b6129989190614b3c565b965085878287602001516001600160681b03166129b5919061485f565b6129bf9190614840565b6129c99190614b3c565b6129d3908261485f565b91508185602001516001600160681b0316846129ef9190614b25565b1015612a3757612a1485602001516001600160681b031684612a119190614b25565b90565b82604051636874461960e01b815260048101929092526024820152604401610bb8565b505b612a8e612a588286602001516001600160681b0316610b62919061485f565b612a7f888a88604001516001600160681b0316612a75919061485f565b610b62919061485f565b866020015187604001516138a7565b612a988d87613f85565b508084602001516001600160681b0316612ab2919061485f565b821115612ac457612ac28c612246565b505b612ace868661485f565b868886604001516001600160681b0316612ae8919061485f565b612af2919061485f565b1015612b115760405163efd61adb60e01b815260040160405180910390fd5b60006001600160a01b038e16337f05e533e65fa7a345b42a006257cdd31febe912eacbbaaa92299c7a931895c5297f000000000000000000000000000000000000000000000000000000006516e670612b698d61400d565b612b7290614b50565b612b7b8d61400d565b612b8490614b50565b612b8d8d61400d565b6040805163ffffffff9095168552602085019390935291830152606082015260800160405180910390a45050505050955095509592505050565b306000908152600160205260408120548154909190819081612be761235c565b905060007f0000000000000000000000000000000000000000000000000000000000000001905060008383604001516001600160681b0316612c299190614b25565b90508015612cb65760208301518990612c4b906001600160681b031683613f70565b1080612c6e575060208301518890612c6c906001600160681b031683613f70565b115b15612cb6576020830151612c8b906001600160681b031682613f70565b604051630cc2a49b60e31b81526004810191909152602481018a905260448101899052606401610bb8565b60008484602001516001600160681b031689612cd29190614840565b612cdc9190614b3c565b905084612ce9838a614840565b612cf39190614b3c565b95508a15612ea6576001600160601b03831673e7a9771c692c428df17ecad6cd58d4938c010a2e6353db875482612d29856123d0565b88602001516001600160681b0316612d419190614877565b612d4b9190614950565b866001600160601b0316612d5e8b6123d0565b89604001516001600160681b0316612d769190614877565b612d809190614950565b876001600160601b0316612d938c6123d0565b612d9d9190614950565b612dc7427f000000000000000000000000000000000000000000000000000000006516e670614776565b7f000000000000000000000000000000000000000000000000000000030640f90e612df58c600001516131f2565b612dfd6135e8565b7f00000000000000000000000000000000000000000000000100000000000000006040518963ffffffff1660e01b8152600401612e41989796959493929190614b6c565b602060405180830381865af4158015612e5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e8291906147e7565b612e8c919061481a565b612e9f906001600160801b03168261485f565b9050600095505b612eec612ec58286602001516001600160681b0316610b629190614b25565b612a7f8a8988604001516001600160681b0316612ee29190614b25565b610b629190614b25565b612ef63089614036565b50612f008d612246565b96508515612f3c57612f3c6001600160a01b037f000000000000000000000000b917a6cd3f811a84c1c5b972e2c715a6d93f40aa168d88613a7a565b612f468886614b25565b888786604001516001600160681b0316612f609190614b25565b612f6a9190614b25565b1015612f895760405163efd61adb60e01b815260040160405180910390fd5b6001600160a01b03808d16908e16337f05e533e65fa7a345b42a006257cdd31febe912eacbbaaa92299c7a931895c5297f000000000000000000000000000000000000000000000000000000006516e670612fe38c61400d565b612fec8c61400d565b612ff58f61400d565b612ffe90614b50565b6040805163ffffffff9095168552602085019390935291830152606082015260800160405180910390a4878514801561305d57507f000000000000000000000000000000000000000000000000000000006516e67063ffffffff164210155b1561308c576040517fc2169c1afcf23c4cd9b64d9eb5091cf93d985c5903ddd02c6c0e78cbbfbf7be490600090a15b5050505050955095509592505050565b60006001600160a01b038316331461313c576001600160a01b0383166000908152600260209081526040808320338452909152902054600019811461313a578281101561312b5760405162461bcd60e51b815260206004820152601c60248201527f45524332303a20496e73756666696369656e7420617070726f76616c000000006044820152606401610bb8565b61313884338584036122bc565b505b505b50600192915050565b6001600160a01b03831660009081526001602052604081205482111561317d5760405162461bcd60e51b8152600401610bb890614bc1565b6001600160a01b0380851660009081526001602052604080822080548690039055918516815220546131b090839061485f565b6001600160a01b038085166000818152600160205260409081902093909355915190861690600080516020614da0833981519152906123139086815260200190565b6000610a8c61271061ffff84166121df565b60007f000000000000000000000000000000000000000000000000000000006516e67063ffffffff16421061324c576040516304ff30ef60e21b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000016001600160601b03811673e7a9771c692c428df17ecad6cd58d4938c010a2e6353db875461329b8389614747565b6132ae6001600160601b03861689614747565b6132c16001600160601b0387168c614950565b6132eb427f000000000000000000000000000000000000000000000000000000006516e670614776565b7f000000000000000000000000000000000000000000000000000000030640f90e8a6133156135e8565b7f00000000000000000000000000000000000000000000000100000000000000006040518963ffffffff1660e01b8152600401613359989796959493929190614aad565b602060405180830381865af4158015613376573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061339a91906147e7565b6133a4919061481a565b9695505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60036040516133e09190614bf8565b60405180910390206133f0610de4565b80516020918201206040805192830194909452928101919091526060810191909152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b6000610a7c7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161349091906143bf565b602060405180830381865afa1580156134ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134d19190614b0c565b6140b4565b6001600160e01b03191660009081526007602052604090206001015460e01b90565b6135028282612325565b15610e3a576001600160e01b0319821660008181526007602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339391927f4ddc7b757e7bdd7254a9cd39452d307a52761bc824625c6a33104a075d8099e691a45050565b6001600160e01b0319811661357d836134d6565b6001600160e01b03191614610e3a576001600160e01b0319828116600081815260076020526040808220600101805463ffffffff191660e087901c17905551928416927fd348e2220a50b4500ec353f6e802d2f14dd1b5d6786148fd1bbcc570bf92d4739190a35050565b6000610a7c670de0b6b3a76400007f00000000000000000000000000000000000000000000000000000000000000016001600160601b0316613628612219565b6136329190614840565b906121df565b6008546040516370a0823160e01b81526000916136e091620100009091046001600160681b0316907f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b0316906370a082319061369f9030906004016143bf565b602060405180830381865afa1580156136bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ee29190614b0c565b9050611c4c6001600160a01b037f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f16836001600160801b038416613a7a565b6000610a8c7f0000000000000000000000000000000000000000000000010000000000000000600f0b836140dd565b600081613767846b033b2e3c9fd0803ce8000000614840565b610b2d9190614b3c565b6000610a7c6000547f000000000000000000000000b917a6cd3f811a84c1c5b972e2c715a6d93f40aa6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016137c591906143bf565b602060405180830381865afa1580156137e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138069190614b0c565b6134d1919061485f565b60007f000000000000000000000000000000000000000000000000000000006516e67063ffffffff164210613858576040516304ff30ef60e21b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000016001600160601b03811673e7a9771c692c428df17ecad6cd58d4938c010a2e63ddfc2beb61329b8389614747565b816001600160681b0316846001600160801b03161480156138d95750806001600160681b0316836001600160801b0316145b613a4b5760085442906000906138fc90600160e01b900463ffffffff1683614776565b60095463ffffffff91909116915080821580159061392357506000856001600160681b0316115b801561393857506000866001600160681b0316115b1561397257613965613952876001600160681b031661371f565b6110ae856001600160681b038916614840565b61396f908261485f565b90505b600880546001600160e01b0316600160e01b63ffffffff871602179055600981905560006139a86001600160801b038a166140b4565b905060006139be896001600160801b03166140b4565b6008805462010000600160e01b031916620100006001600160681b03868116918202600160781b600160e01b03191692909217600160781b9285169283021790925560408051928352602083019190915281018590529091507f17be3acebd510daa18778e1ee1fbaf88237b124dc0803c3be2fd4f99f3e69d339060600160405180910390a15050505050505b50505050565b600060016001607f1b038211156123f95760405162461bcd60e51b8152600401610bb890614a86565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691613ad69190614c97565b6000604051808303816000865af19150503d8060008114613b13576040519150601f19603f3d011682016040523d82523d6000602084013e613b18565b606091505b5091509150818015613b2e5750613b2e81614148565b613b5457613b3b81614169565b60405162461bcd60e51b8152600401610bb89190614226565b5050505050565b6000613b887f0000000000000000000000000000000000000000000000000000000000000012600a614a7a565b613b90612219565b613b9861343f565b6001600160681b0316613bab9190614840565b610a7c9190614b3c565b613bbf8282612325565b610e3a576001600160e01b0319821660008181526007602090815260408083206001600160a01b0386168085529252808320805460ff1916600117905551339391927fe6231789d19137da31d0550f4ba9ee379020a8cfb64cb79bf1790c996d2e616591a45050565b60007f000000000000000000000000000000000000000000000000000000006516e67063ffffffff164210613c70576040516304ff30ef60e21b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000016001600160601b03811673e7a9771c692c428df17ecad6cd58d4938c010a2e632544b5c5613cbf8389614950565b613cd26001600160601b03861689614950565b613ce56001600160601b0387168c614950565b613d0f427f000000000000000000000000000000000000000000000000000000006516e670614776565b7f000000000000000000000000000000000000000000000000000000030640f90e8a613d396135e8565b7f00000000000000000000000000000000000000000000000100000000000000006040518963ffffffff1660e01b8152600401613d7d989796959493929190614b6c565b602060405180830381865af4158015613d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dbe91906147e7565b613dc8919061481a565b91506000613ddc610b626125cc85896148b1565b90506001600160801b038116613df28887614877565b6001600160801b031610156126375761261b8786614877565b600081600003613e1a57600080fd5b60006001600160c01b038411613e455782604085901b81613e3d57613e3d614804565b049050613f5c565b60c084811c6401000000008110613e5e576020918201911c5b620100008110613e70576010918201911c5b6101008110613e81576008918201911c5b60108110613e91576004918201911c5b60048110613ea1576002918201911c5b60028110613eb0576001820191505b60bf820360018603901c6001018260ff0387901b81613ed157613ed1614804565b0492506001600160801b03831115613ee857600080fd5b608085901c83026001600160801b038616840260c088901c604089901b82811015613f14576001820391505b608084901b92900382811015613f2b576001820391505b829003608084901c8214613f4157613f41614cb3565b888181613f5057613f50614804565b04870196505050505050505b6001600160801b03811115610b2d57600080fd5b60008161376784670de0b6b3a7640000614840565b6001600160a01b038216600090815260016020526040812054613fa990839061485f565b6001600160a01b03841660009081526001602052604081209190915554613fd190839061485f565b60009081556040518381526001600160a01b0385169190600080516020614da0833981519152906020015b60405180910390a350600192915050565b60006001600160ff1b038211156123f95760405162461bcd60e51b8152600401610bb890614a86565b6001600160a01b03821660009081526001602052604081205482111561406e5760405162461bcd60e51b8152600401610bb890614bc1565b6001600160a01b0383166000818152600160209081526040808320805487900390558254869003835551858152919291600080516020614da08339815191529101613ffc565b60006001600160681b038211156123f95760405162461bcd60e51b8152600401610bb890614a86565b6000816000036140ef57506000610a8c565b600083600f0b121561410057600080fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b0381111561412f57600080fd5b60401b811981111561414057600080fd5b019392505050565b6000815160001480610a8c575081806020019051810190610a8c9190614cc9565b60606044825110156141ae57505060408051808201909152601d81527f5472616e73616374696f6e2072657665727465642073696c656e746c79000000602082015290565b60048201915081806020019051810190610a8c9190614ceb565b80356001600160a01b0381168114611c4c57600080fd5b6000602082840312156141f157600080fd5b610b2d826141c8565b60005b838110156142155781810151838201526020016141fd565b83811115613a4b5750506000910152565b60208152600082518060208401526142458160408501602087016141fa565b601f01601f19169190910160400192915050565b6000806040838503121561426c57600080fd5b614275836141c8565b946020939093013593505050565b80356001600160e01b031981168114611c4c57600080fd5b600080604083850312156142ae57600080fd5b6142b783614283565b91506142c5602084016141c8565b90509250929050565b6001600160801b03811681146142e357600080fd5b50565b6000602082840312156142f857600080fd5b8135610b2d816142ce565b600080600080600060a0868803121561431b57600080fd5b614324866141c8565b9450614332602087016141c8565b94979496505050506040830135926060810135926080909101359150565b60008060006060848603121561436557600080fd5b61436e846141c8565b95602085013595506040909401359392505050565b60008060006060848603121561439857600080fd5b6143a1846141c8565b92506143af602085016141c8565b9150604084013590509250925092565b6001600160a01b0391909116815260200190565b6000602082840312156143e557600080fd5b610b2d82614283565b60006020828403121561440057600080fd5b5035919050565b60008060006060848603121561441c57600080fd5b614425846141c8565b92506020840135614435816142ce565b91506040840135614445816142ce565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561448f5761448f614450565b604052919050565b600080604083850312156144aa57600080fd5b823567ffffffffffffffff808211156144c257600080fd5b818501915085601f8301126144d657600080fd5b81356020828211156144ea576144ea614450565b8160051b92506144fb818401614466565b828152928401810192818101908985111561451557600080fd5b948201945b8486101561453a5761452b86614283565b8252948201949082019061451a565b965061454990508782016141c8565b9450505050509250929050565b6000806040838503121561456957600080fd5b61457283614283565b91506142c560208401614283565b6000806000806080858703121561459657600080fd5b61459f856141c8565b93506145ad602086016141c8565b93969395505050506040820135916060013590565b600080604083850312156145d557600080fd5b6145de836141c8565b915060208301356145ee816142ce565b809150509250929050565b60006020828403121561460b57600080fd5b813561ffff81168114610b2d57600080fd5b600080600080600080600060e0888a03121561463857600080fd5b614641886141c8565b965061464f602089016141c8565b95506040880135945060608801359350608088013560ff8116811461467357600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156146a357600080fd5b6142b7836141c8565b600181811c908216806146c057607f821691505b6020821081036146e057634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600d908201526c1058d8d95cdcc819195b9a5959609a1b604082015260600190565b6020808252600a908201526927b7363c9030b236b4b760b11b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60006001600160681b038083168185168183048111821515161561476d5761476d614731565b02949350505050565b600063ffffffff8381169083168181101561479357614793614731565b039392505050565b6001600160681b03978816815295909616602086015263ffffffff939093166040850152600f91820b6060850152810b608084015290810b60a08301529190910b60c082015260e00190565b6000602082840312156147f957600080fd5b8151610b2d816142ce565b634e487b7160e01b600052601260045260246000fd5b60006001600160801b038381168061483457614834614804565b92169190910492915050565b600081600019048311821515161561485a5761485a614731565b500290565b6000821982111561487257614872614731565b500190565b60006001600160801b038381169083168181101561479357614793614731565b6001600160801b0392831681529116602082015260400190565b60006001600160801b038281168482168083038211156148d3576148d3614731565b01949350505050565b6000600f82900b6001607f1b81016148f6576148f6614731565b60000392915050565b63ffffffff939093168352600f91820b6020840152900b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60006001820161494957614949614731565b5060010190565b60006001600160801b038281168482168115158284048211161561476d5761476d614731565b60006001600160681b038381169083168181101561479357614793614731565b600181815b808511156149d15781600019048211156149b7576149b7614731565b808516156149c457918102915b93841c939080029061499b565b509250929050565b6000826149e857506001610a8c565b816149f557506000610a8c565b8160018114614a0b5760028114614a1557614a31565b6001915050610a8c565b60ff841115614a2657614a26614731565b50506001821b610a8c565b5060208310610133831016604e8410600b8410161715614a54575081810a610a8c565b614a5e8383614996565b8060001904821115614a7257614a72614731565b029392505050565b6000610b2d83836149d9565b6020808252600d908201526c43617374206f766572666c6f7760981b604082015260600190565b6001600160681b0398891681529690971660208701526001600160801b0394909416604086015263ffffffff929092166060850152600f90810b608085015290810b60a084015290810b60c08301529190910b60e08201526101000190565b600060208284031215614b1e57600080fd5b5051919050565b600082821015614b3757614b37614731565b500390565b600082614b4b57614b4b614804565b500490565b6000600160ff1b8201614b6557614b65614731565b5060000390565b6001600160801b039889168152968816602088015294909616604086015263ffffffff929092166060850152600f90810b608085015290810b60a084015292830b60c083015290910b60e08201526101000190565b6020808252601b908201527f45524332303a20496e73756666696369656e742062616c616e63650000000000604082015260600190565b600080835481600182811c915080831680614c1457607f831692505b60208084108203614c3357634e487b7160e01b86526022600452602486fd5b818015614c475760018114614c5c57614c89565b60ff1986168952841515850289019650614c89565b60008a81526020902060005b86811015614c815781548b820152908501908301614c68565b505084890196505b509498975050505050505050565b60008251614ca98184602087016141fa565b9190910192915050565b634e487b7160e01b600052600160045260246000fd5b600060208284031215614cdb57600080fd5b81518015158114610b2d57600080fd5b600060208284031215614cfd57600080fd5b815167ffffffffffffffff80821115614d1557600080fd5b818401915084601f830112614d2957600080fd5b815181811115614d3b57614d3b614450565b614d4e601f8201601f1916602001614466565b9150808252856020828501011115614d6557600080fd5b614d768160208401602086016141fa565b5094935050505056feb8aaa3347fac66c4197e2ddb56d1b1e06fa6f7ae158c01cb2e7f9f9efb4975bbddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212203b6635fce2aa77dc7c76581d3cf2fb896ce3ea866c647eb42827a3db63d850c664736f6c634300080f0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.