Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
PoolCommons
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 0 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import { PRBMathSD59x18 } from "@prb-math/contracts/PRBMathSD59x18.sol"; import { PRBMathUD60x18 } from "@prb-math/contracts/PRBMathUD60x18.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { DepositsState, EmaState, InflatorState, InterestState, PoolBalancesState, PoolState } from '../../interfaces/pool/commons/IPoolState.sol'; import { IERC3156FlashBorrower } from '../../interfaces/pool/IERC3156FlashBorrower.sol'; import { _dwatp, _htp, _indexOf, MAX_FENWICK_INDEX, MIN_PRICE, MAX_PRICE } from '../helpers/PoolHelper.sol'; import { Deposits } from '../internal/Deposits.sol'; import { Buckets } from '../internal/Buckets.sol'; import { Loans } from '../internal/Loans.sol'; import { Maths } from '../internal/Maths.sol'; /** @title PoolCommons library @notice External library containing logic for common pool functionality: - interest rate accrual and interest rate params update - pool utilization */ library PoolCommons { using SafeERC20 for IERC20; /*****************/ /*** Constants ***/ /*****************/ uint256 internal constant CUBIC_ROOT_1000000 = 100 * 1e18; uint256 internal constant ONE_THIRD = 0.333333333333333334 * 1e18; uint256 internal constant INCREASE_COEFFICIENT = 1.1 * 1e18; uint256 internal constant DECREASE_COEFFICIENT = 0.9 * 1e18; int256 internal constant PERCENT_102 = 1.02 * 1e18; int256 internal constant NEG_H_MAU_HOURS = -0.057762265046662105 * 1e18; // -ln(2)/12 int256 internal constant NEG_H_TU_HOURS = -0.008251752149523158 * 1e18; // -ln(2)/84 /**************/ /*** Events ***/ /**************/ // See `IPoolEvents` for descriptions event Flashloan(address indexed receiver, address indexed token, uint256 amount); event ResetInterestRate(uint256 oldRate, uint256 newRate); event UpdateInterestRate(uint256 oldRate, uint256 newRate); /**************/ /*** Errors ***/ /**************/ // See `IPoolErrors` for descriptions error FlashloanCallbackFailed(); error FlashloanIncorrectBalance(); /*************************/ /*** Local Var Structs ***/ /*************************/ /// @dev Struct used for `updateInterestState` function local vars. struct UpdateInterestLocalVars { uint256 debtEma; uint256 depositEma; uint256 debtColEma; uint256 lupt0DebtEma; uint256 t0Debt2ToCollateral; uint256 newMeaningfulDeposit; uint256 newDebt; uint256 newDebtCol; uint256 newLupt0Debt; uint256 lastEmaUpdate; int256 elapsed; int256 weightMau; int256 weightTu; uint256 newInterestRate; uint256 nonAuctionedT0Debt; } /**************************/ /*** External Functions ***/ /**************************/ /** * @notice Calculates EMAs, caches values required for calculating interest rate, and saves new values in storage. * @notice Calculates new pool interest rate (Never called more than once every 12 hours) and saves new values in storage. * @dev === Write state === * @dev `EMA`s state * @dev interest rate accumulator and `interestRateUpdate` state * @dev === Emit events === * @dev - `UpdateInterestRate` / `ResetInterestRate` */ function updateInterestState( InterestState storage interestParams_, EmaState storage emaParams_, DepositsState storage deposits_, PoolState memory poolState_, uint256 lup_ ) external { UpdateInterestLocalVars memory vars; // load existing EMA values vars.debtEma = emaParams_.debtEma; vars.depositEma = emaParams_.depositEma; vars.debtColEma = emaParams_.debtColEma; vars.lupt0DebtEma = emaParams_.lupt0DebtEma; vars.lastEmaUpdate = emaParams_.emaUpdate; vars.t0Debt2ToCollateral = interestParams_.t0Debt2ToCollateral; // calculate new interest params vars.nonAuctionedT0Debt = poolState_.t0Debt - poolState_.t0DebtInAuction; vars.newDebt = Maths.wmul(vars.nonAuctionedT0Debt, poolState_.inflator); // new meaningful deposit cannot be less than pool's debt vars.newMeaningfulDeposit = Maths.max( _meaningfulDeposit( deposits_, poolState_.t0DebtInAuction, vars.nonAuctionedT0Debt, poolState_.inflator, vars.t0Debt2ToCollateral ), vars.newDebt ); vars.newDebtCol = Maths.wmul(poolState_.inflator, vars.t0Debt2ToCollateral); vars.newLupt0Debt = Maths.wmul(lup_, vars.nonAuctionedT0Debt); // update EMAs only once per block if (vars.lastEmaUpdate != block.timestamp) { // first time EMAs are updated, initialize EMAs if (vars.lastEmaUpdate == 0) { vars.debtEma = vars.newDebt; vars.depositEma = vars.newMeaningfulDeposit; vars.debtColEma = vars.newDebtCol; vars.lupt0DebtEma = vars.newLupt0Debt; } else { vars.elapsed = int256(Maths.wdiv(block.timestamp - vars.lastEmaUpdate, 1 hours)); vars.weightMau = PRBMathSD59x18.exp(PRBMathSD59x18.mul(NEG_H_MAU_HOURS, vars.elapsed)); vars.weightTu = PRBMathSD59x18.exp(PRBMathSD59x18.mul(NEG_H_TU_HOURS, vars.elapsed)); // calculate the t0 debt EMA, used for MAU vars.debtEma = uint256( PRBMathSD59x18.mul(vars.weightMau, int256(vars.debtEma)) + PRBMathSD59x18.mul(1e18 - vars.weightMau, int256(interestParams_.debt)) ); // update the meaningful deposit EMA, used for MAU vars.depositEma = uint256( PRBMathSD59x18.mul(vars.weightMau, int256(vars.depositEma)) + PRBMathSD59x18.mul(1e18 - vars.weightMau, int256(interestParams_.meaningfulDeposit)) ); // calculate the debt squared to collateral EMA, used for TU vars.debtColEma = uint256( PRBMathSD59x18.mul(vars.weightTu, int256(vars.debtColEma)) + PRBMathSD59x18.mul(1e18 - vars.weightTu, int256(interestParams_.debtCol)) ); // calculate the EMA of LUP * t0 debt vars.lupt0DebtEma = uint256( PRBMathSD59x18.mul(vars.weightTu, int256(vars.lupt0DebtEma)) + PRBMathSD59x18.mul(1e18 - vars.weightTu, int256(interestParams_.lupt0Debt)) ); } // save EMAs in storage emaParams_.debtEma = vars.debtEma; emaParams_.depositEma = vars.depositEma; emaParams_.debtColEma = vars.debtColEma; emaParams_.lupt0DebtEma = vars.lupt0DebtEma; // save last EMA update time emaParams_.emaUpdate = block.timestamp; } // reset interest rate if pool rate > 10% and debtEma < 5% of depositEma if ( poolState_.rate > 0.1 * 1e18 && vars.debtEma < Maths.wmul(vars.depositEma, 0.05 * 1e18) ) { interestParams_.interestRate = uint208(0.1 * 1e18); interestParams_.interestRateUpdate = uint48(block.timestamp); emit ResetInterestRate( poolState_.rate, 0.1 * 1e18 ); } // otherwise calculate and update interest rate if it has been more than 12 hours since the last update else if (block.timestamp - interestParams_.interestRateUpdate > 12 hours) { vars.newInterestRate = _calculateInterestRate( poolState_, vars.debtEma, vars.depositEma, vars.debtColEma, vars.lupt0DebtEma ); if (poolState_.rate != vars.newInterestRate) { interestParams_.interestRate = uint208(vars.newInterestRate); interestParams_.interestRateUpdate = uint48(block.timestamp); emit UpdateInterestRate( poolState_.rate, vars.newInterestRate ); } } // save new interest rate params to storage interestParams_.debt = vars.newDebt; interestParams_.meaningfulDeposit = vars.newMeaningfulDeposit; interestParams_.debtCol = vars.newDebtCol; interestParams_.lupt0Debt = vars.newLupt0Debt; } /** * @notice Calculates new pool interest and scale the fenwick tree to update amount of debt owed to lenders (saved in storage). * @dev === Write state === * @dev - `Deposits.mult` (scale `Fenwick` tree with new interest accrued): * @dev update `scaling` array state * @param emaParams_ Struct for pool `EMA`s state. * @param deposits_ Struct for pool deposits state. * @param poolState_ Current state of the pool. * @param maxT0DebtToCollateral_ Max t0 debt to collateral in Pool. * @param elapsed_ Time elapsed since last inflator update. * @return newInflator_ The new value of pool inflator. * @return newInterest_ The new interest accrued. */ function accrueInterest( EmaState storage emaParams_, DepositsState storage deposits_, PoolState calldata poolState_, uint256 maxT0DebtToCollateral_, uint256 elapsed_ ) external returns (uint256 newInflator_, uint256 newInterest_) { // Scale the borrower inflator to update amount of interest owed by borrowers uint256 pendingFactor = PRBMathUD60x18.exp((poolState_.rate * elapsed_) / 365 days); // calculate the highest threshold price newInflator_ = Maths.wmul(poolState_.inflator, pendingFactor); uint256 htp = _htp(maxT0DebtToCollateral_, poolState_.inflator); uint256 accrualIndex; if (htp > MAX_PRICE) accrualIndex = 1; // if HTP is over the highest price bucket then no buckets earn interest else if (htp < MIN_PRICE) accrualIndex = MAX_FENWICK_INDEX; // if HTP is under the lowest price bucket then all buckets earn interest else accrualIndex = _indexOf(htp); // else HTP bucket earn interest uint256 lupIndex = Deposits.findIndexOfSum(deposits_, poolState_.debt); // accrual price is less of lup and htp, and prices decrease as index increases if (lupIndex > accrualIndex) accrualIndex = lupIndex; uint256 interestEarningDeposit = Deposits.prefixSum(deposits_, accrualIndex); if (interestEarningDeposit != 0) { newInterest_ = Maths.wmul( _lenderInterestMargin(_utilization(emaParams_.debtEma, emaParams_.depositEma)), Maths.wmul(pendingFactor - Maths.WAD, poolState_.debt) ); // lender factor computation, capped at 10x the interest factor for borrowers uint256 lenderFactor = Maths.min( Maths.floorWdiv(newInterest_, interestEarningDeposit), Maths.wmul(pendingFactor - Maths.WAD, Maths.wad(10)) ) + Maths.WAD; // Scale the fenwick tree to update amount of debt owed to lenders Deposits.mult(deposits_, accrualIndex, lenderFactor); } } /** * @notice Executes a flashloan from current pool. * @dev === Reverts on === * @dev - `FlashloanCallbackFailed()` if receiver is not an `ERC3156FlashBorrower` * @dev - `FlashloanIncorrectBalance()` if pool balance after flashloan is different than initial balance * @param receiver_ Address of the contract which implements the appropriate interface to receive tokens. * @param token_ Address of the `ERC20` token caller wants to borrow. * @param amount_ The denormalized amount (dependent upon token precision) of tokens to borrow. * @param data_ User-defined calldata passed to the receiver. */ function flashLoan( IERC3156FlashBorrower receiver_, address token_, uint256 amount_, bytes calldata data_ ) external { IERC20 tokenContract = IERC20(token_); uint256 initialBalance = tokenContract.balanceOf(address(this)); tokenContract.safeTransfer( address(receiver_), amount_ ); if (receiver_.onFlashLoan(msg.sender, token_, amount_, 0, data_) != keccak256("ERC3156FlashBorrower.onFlashLoan")) revert FlashloanCallbackFailed(); tokenContract.safeTransferFrom( address(receiver_), address(this), amount_ ); if (tokenContract.balanceOf(address(this)) != initialBalance) revert FlashloanIncorrectBalance(); emit Flashloan(address(receiver_), token_, amount_); } /**************************/ /*** Internal Functions ***/ /**************************/ /** * @notice Calculates new pool interest rate. */ function _calculateInterestRate( PoolState memory poolState_, uint256 debtEma_, uint256 depositEma_, uint256 debtColEma_, uint256 lupt0DebtEma_ ) internal pure returns (uint256 newInterestRate_) { // meaningful actual utilization int256 mau; // meaningful actual utilization * 1.02 int256 mau102; if (poolState_.debt != 0) { // calculate meaningful actual utilization for interest rate update mau = int256(_utilization(debtEma_, depositEma_)); mau102 = (mau * PERCENT_102) / 1e18; } // calculate target utilization int256 tu = (lupt0DebtEma_ != 0) ? int256(Maths.wdiv(debtColEma_, lupt0DebtEma_)) : int(Maths.WAD); newInterestRate_ = poolState_.rate; // raise rates if 4*(tu-1.02*mau) < (tu+1.02*mau-1)^2-1 if (4 * (tu - mau102) < (((tu + mau102 - 1e18) / 1e9) ** 2) - 1e18) { newInterestRate_ = Maths.wmul(poolState_.rate, INCREASE_COEFFICIENT); // decrease rates if 4*(tu-mau) > 1-(tu+mau-1)^2 } else if (4 * (tu - mau) > 1e18 - ((tu + mau - 1e18) / 1e9) ** 2) { newInterestRate_ = Maths.wmul(poolState_.rate, DECREASE_COEFFICIENT); } // bound rates between 10 bps and 400% newInterestRate_ = Maths.min(4 * 1e18, Maths.max(0.001 * 1e18, newInterestRate_)); } /** * @notice Calculates pool meaningful actual utilization. * @param debtEma_ `EMA` of pool debt. * @param depositEma_ `EMA` of meaningful pool deposit. * @return utilization_ Pool meaningful actual utilization value. */ function _utilization( uint256 debtEma_, uint256 depositEma_ ) internal pure returns (uint256 utilization_) { if (depositEma_ != 0) utilization_ = Maths.wdiv(debtEma_, depositEma_); } /** * @notice Calculates lender interest margin. * @param mau_ Meaningful actual utilization. * @return The lender interest margin value. */ function _lenderInterestMargin( uint256 mau_ ) internal pure returns (uint256) { // Net Interest Margin = ((1 - MAU1)^(1/3) * 0.15) // Where MAU1 is MAU capped at 100% (min(MAU,1)) // Lender Interest Margin = 1 - Net Interest Margin // PRBMath library forbids raising a number < 1e18 to a power. Using the product and quotient rules of // exponents, rewrite the equation with a coefficient s which provides sufficient precision: // Net Interest Margin = ((1 - MAU1) * s)^(1/3) / s^(1/3) * 0.15 uint256 base = 1_000_000 * 1e18 - Maths.min(mau_, 1e18) * 1_000_000; // If unutilized deposit is infinitessimal, lenders get 100% of interest. if (base < 1e18) { return 1e18; } else { // cubic root of the percentage of meaningful unutilized deposit uint256 crpud = PRBMathUD60x18.pow(base, ONE_THIRD); // finish calculating Net Interest Margin, and then convert to Lender Interest Margin return 1e18 - Maths.wdiv(Maths.wmul(crpud, 0.15 * 1e18), CUBIC_ROOT_1000000); } } /** * @notice Calculates pool's meaningful deposit. * @param deposits_ Struct for pool deposits state. * @param t0DebtInAuction_ Value of pool's t0 debt currently in auction. * @param nonAuctionedT0Debt_ Value of pool's t0 debt that is not in auction. * @param inflator_ Pool's current inflator. * @param t0Debt2ToCollateral_ `t0Debt2ToCollateral` ratio. * @return meaningfulDeposit_ Pool's meaningful deposit. */ function _meaningfulDeposit( DepositsState storage deposits_, uint256 t0DebtInAuction_, uint256 nonAuctionedT0Debt_, uint256 inflator_, uint256 t0Debt2ToCollateral_ ) internal view returns (uint256 meaningfulDeposit_) { uint256 dwatp = _dwatp(nonAuctionedT0Debt_, inflator_, t0Debt2ToCollateral_); if (dwatp == 0) { meaningfulDeposit_ = Deposits.treeSum(deposits_); } else { if (dwatp >= MAX_PRICE) meaningfulDeposit_ = 0; else if (dwatp >= MIN_PRICE) meaningfulDeposit_ = Deposits.prefixSum(deposits_, _indexOf(dwatp)); else meaningfulDeposit_ = Deposits.treeSum(deposits_); } meaningfulDeposit_ -= Maths.min( meaningfulDeposit_, Maths.wmul(t0DebtInAuction_, inflator_) ); } /**********************/ /*** View Functions ***/ /**********************/ /** * @notice Calculates pool related debt values. * @param poolBalances_ Pool debt * @param inflatorState_ Interest inflator and last update time * @param interestState_ Interest rate and t0Debt2ToCollateral accumulator * @return Current amount of debt owed by borrowers in pool. * @return Debt owed by borrowers based on last inflator snapshot. * @return Total amount of debt in auction. * @return t0debt accross all borrowers divided by their collateral, used in determining a collateralization weighted debt. */ function debtInfo( PoolBalancesState memory poolBalances_, InflatorState memory inflatorState_, InterestState memory interestState_ ) external view returns (uint256, uint256, uint256, uint256) { uint256 t0Debt = poolBalances_.t0Debt; uint256 inflator = inflatorState_.inflator; return ( Maths.ceilWmul( t0Debt, pendingInflator(inflator, inflatorState_.inflatorUpdate, interestState_.interestRate) ), Maths.ceilWmul(t0Debt, inflator), Maths.ceilWmul(poolBalances_.t0DebtInAuction, inflator), interestState_.t0Debt2ToCollateral ); } /** * @notice Calculates pool interest factor for a given interest rate and time elapsed since last inflator update. * @param interestRate_ Current pool interest rate. * @param elapsed_ Time elapsed since last inflator update. * @return The value of pool interest factor. */ function pendingInterestFactor( uint256 interestRate_, uint256 elapsed_ ) external pure returns (uint256) { return PRBMathUD60x18.exp((interestRate_ * elapsed_) / 365 days); } /** * @notice Calculates pool pending inflator given the current inflator, time of last update and current interest rate. * @param inflator_ Current pool inflator. * @param inflatorUpdate Timestamp when inflator was updated. * @param interestRate_ The interest rate of the pool. * @return The pending value of pool inflator. */ function pendingInflator( uint256 inflator_, uint256 inflatorUpdate, uint256 interestRate_ ) public view returns (uint256) { return Maths.wmul( inflator_, PRBMathUD60x18.exp((interestRate_ * (block.timestamp - inflatorUpdate)) / 365 days) ); } /** * @notice Calculates lender interest margin for a given meaningful actual utilization. * @dev Wrapper of the internal function. */ function lenderInterestMargin( uint256 mau_ ) external pure returns (uint256) { return _lenderInterestMargin(mau_); } /** * @notice Calculates pool meaningful actual utilization. * @dev Wrapper of the internal function. */ function utilization( EmaState storage emaParams_ ) external view returns (uint256 utilization_) { return _utilization(emaParams_.debtEma, emaParams_.depositEma); } }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; import "./PRBMath.sol"; /// @title PRBMathSD59x18 /// @author Paul Razvan Berg /// @notice Smart contract library for advanced fixed-point math that works with int256 numbers considered to have 18 /// trailing decimals. We call this number representation signed 59.18-decimal fixed-point, since the numbers can have /// a sign and there can be up to 59 digits in the integer part and up to 18 decimals in the fractional part. The numbers /// are bound by the minimum and the maximum values permitted by the Solidity type int256. library PRBMathSD59x18 { /// @dev log2(e) as a signed 59.18-decimal fixed-point number. int256 internal constant LOG2_E = 1_442695040888963407; /// @dev Half the SCALE number. int256 internal constant HALF_SCALE = 5e17; /// @dev The maximum value a signed 59.18-decimal fixed-point number can have. int256 internal constant MAX_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_792003956564819967; /// @dev The maximum whole value a signed 59.18-decimal fixed-point number can have. int256 internal constant MAX_WHOLE_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_000000000000000000; /// @dev The minimum value a signed 59.18-decimal fixed-point number can have. int256 internal constant MIN_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_792003956564819968; /// @dev The minimum whole value a signed 59.18-decimal fixed-point number can have. int256 internal constant MIN_WHOLE_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_000000000000000000; /// @dev How many trailing decimals can be represented. int256 internal constant SCALE = 1e18; /// INTERNAL FUNCTIONS /// /// @notice Calculate the absolute value of x. /// /// @dev Requirements: /// - x must be greater than MIN_SD59x18. /// /// @param x The number to calculate the absolute value for. /// @param result The absolute value of x. function abs(int256 x) internal pure returns (int256 result) { unchecked { if (x == MIN_SD59x18) { revert PRBMathSD59x18__AbsInputTooSmall(); } result = x < 0 ? -x : x; } } /// @notice Calculates the arithmetic average of x and y, rounding down. /// @param x The first operand as a signed 59.18-decimal fixed-point number. /// @param y The second operand as a signed 59.18-decimal fixed-point number. /// @return result The arithmetic average as a signed 59.18-decimal fixed-point number. function avg(int256 x, int256 y) internal pure returns (int256 result) { // The operations can never overflow. unchecked { int256 sum = (x >> 1) + (y >> 1); if (sum < 0) { // If at least one of x and y is odd, we add 1 to the result. This is because shifting negative numbers to the // right rounds down to infinity. assembly { result := add(sum, and(or(x, y), 1)) } } else { // If both x and y are odd, we add 1 to the result. This is because if both numbers are odd, the 0.5 // remainder gets truncated twice. result = sum + (x & y & 1); } } } /// @notice Yields the least greatest signed 59.18 decimal fixed-point number greater than or equal to x. /// /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x must be less than or equal to MAX_WHOLE_SD59x18. /// /// @param x The signed 59.18-decimal fixed-point number to ceil. /// @param result The least integer greater than or equal to x, as a signed 58.18-decimal fixed-point number. function ceil(int256 x) internal pure returns (int256 result) { if (x > MAX_WHOLE_SD59x18) { revert PRBMathSD59x18__CeilOverflow(x); } unchecked { int256 remainder = x % SCALE; if (remainder == 0) { result = x; } else { // Solidity uses C fmod style, which returns a modulus with the same sign as x. result = x - remainder; if (x > 0) { result += SCALE; } } } } /// @notice Divides two signed 59.18-decimal fixed-point numbers, returning a new signed 59.18-decimal fixed-point number. /// /// @dev Variant of "mulDiv" that works with signed numbers. Works by computing the signs and the absolute values separately. /// /// Requirements: /// - All from "PRBMath.mulDiv". /// - None of the inputs can be MIN_SD59x18. /// - The denominator cannot be zero. /// - The result must fit within int256. /// /// Caveats: /// - All from "PRBMath.mulDiv". /// /// @param x The numerator as a signed 59.18-decimal fixed-point number. /// @param y The denominator as a signed 59.18-decimal fixed-point number. /// @param result The quotient as a signed 59.18-decimal fixed-point number. function div(int256 x, int256 y) internal pure returns (int256 result) { if (x == MIN_SD59x18 || y == MIN_SD59x18) { revert PRBMathSD59x18__DivInputTooSmall(); } // Get hold of the absolute values of x and y. uint256 ax; uint256 ay; unchecked { ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); } // Compute the absolute value of (x*SCALE)÷y. The result must fit within int256. uint256 rAbs = PRBMath.mulDiv(ax, uint256(SCALE), ay); if (rAbs > uint256(MAX_SD59x18)) { revert PRBMathSD59x18__DivOverflow(rAbs); } // Get the signs of x and y. uint256 sx; uint256 sy; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) } // XOR over sx and sy. This is basically checking whether the inputs have the same sign. If yes, the result // should be positive. Otherwise, it should be negative. result = sx ^ sy == 1 ? -int256(rAbs) : int256(rAbs); } /// @notice Returns Euler's number as a signed 59.18-decimal fixed-point number. /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant). function e() internal pure returns (int256 result) { result = 2_718281828459045235; } /// @notice Calculates the natural exponent of x. /// /// @dev Based on the insight that e^x = 2^(x * log2(e)). /// /// Requirements: /// - All from "log2". /// - x must be less than 133.084258667509499441. /// /// Caveats: /// - All from "exp2". /// - For any x less than -41.446531673892822322, the result is zero. /// /// @param x The exponent as a signed 59.18-decimal fixed-point number. /// @return result The result as a signed 59.18-decimal fixed-point number. function exp(int256 x) internal pure returns (int256 result) { // Without this check, the value passed to "exp2" would be less than -59.794705707972522261. if (x < -41_446531673892822322) { return 0; } // Without this check, the value passed to "exp2" would be greater than 192. if (x >= 133_084258667509499441) { revert PRBMathSD59x18__ExpInputTooBig(x); } // Do the fixed-point multiplication inline to save gas. unchecked { int256 doubleScaleProduct = x * LOG2_E; result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// /// @dev See https://ethereum.stackexchange.com/q/79903/24693. /// /// Requirements: /// - x must be 192 or less. /// - The result must fit within MAX_SD59x18. /// /// Caveats: /// - For any x less than -59.794705707972522261, the result is zero. /// /// @param x The exponent as a signed 59.18-decimal fixed-point number. /// @return result The result as a signed 59.18-decimal fixed-point number. function exp2(int256 x) internal pure returns (int256 result) { // This works because 2^(-x) = 1/2^x. if (x < 0) { // 2^59.794705707972522262 is the maximum number whose inverse does not truncate down to zero. if (x < -59_794705707972522261) { return 0; } // Do the fixed-point inversion inline to save gas. The numerator is SCALE * SCALE. unchecked { result = 1e36 / exp2(-x); } } else { // 2^192 doesn't fit within the 192.64-bit format used internally in this function. if (x >= 192e18) { revert PRBMathSD59x18__Exp2InputTooBig(x); } unchecked { // Convert x to the 192.64-bit fixed-point format. uint256 x192x64 = (uint256(x) << 64) / uint256(SCALE); // Safe to convert the result to int256 directly because the maximum input allowed is 192. result = int256(PRBMath.exp2(x192x64)); } } } /// @notice Yields the greatest signed 59.18 decimal fixed-point number less than or equal to x. /// /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x must be greater than or equal to MIN_WHOLE_SD59x18. /// /// @param x The signed 59.18-decimal fixed-point number to floor. /// @param result The greatest integer less than or equal to x, as a signed 58.18-decimal fixed-point number. function floor(int256 x) internal pure returns (int256 result) { if (x < MIN_WHOLE_SD59x18) { revert PRBMathSD59x18__FloorUnderflow(x); } unchecked { int256 remainder = x % SCALE; if (remainder == 0) { result = x; } else { // Solidity uses C fmod style, which returns a modulus with the same sign as x. result = x - remainder; if (x < 0) { result -= SCALE; } } } } /// @notice Yields the excess beyond the floor of x for positive numbers and the part of the number to the right /// of the radix point for negative numbers. /// @dev Based on the odd function definition. https://en.wikipedia.org/wiki/Fractional_part /// @param x The signed 59.18-decimal fixed-point number to get the fractional part of. /// @param result The fractional part of x as a signed 59.18-decimal fixed-point number. function frac(int256 x) internal pure returns (int256 result) { unchecked { result = x % SCALE; } } /// @notice Converts a number from basic integer form to signed 59.18-decimal fixed-point representation. /// /// @dev Requirements: /// - x must be greater than or equal to MIN_SD59x18 divided by SCALE. /// - x must be less than or equal to MAX_SD59x18 divided by SCALE. /// /// @param x The basic integer to convert. /// @param result The same number in signed 59.18-decimal fixed-point representation. function fromInt(int256 x) internal pure returns (int256 result) { unchecked { if (x < MIN_SD59x18 / SCALE) { revert PRBMathSD59x18__FromIntUnderflow(x); } if (x > MAX_SD59x18 / SCALE) { revert PRBMathSD59x18__FromIntOverflow(x); } result = x * SCALE; } } /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down. /// /// @dev Requirements: /// - x * y must fit within MAX_SD59x18, lest it overflows. /// - x * y cannot be negative. /// /// @param x The first operand as a signed 59.18-decimal fixed-point number. /// @param y The second operand as a signed 59.18-decimal fixed-point number. /// @return result The result as a signed 59.18-decimal fixed-point number. function gm(int256 x, int256 y) internal pure returns (int256 result) { if (x == 0) { return 0; } unchecked { // Checking for overflow this way is faster than letting Solidity do it. int256 xy = x * y; if (xy / x != y) { revert PRBMathSD59x18__GmOverflow(x, y); } // The product cannot be negative. if (xy < 0) { revert PRBMathSD59x18__GmNegativeProduct(x, y); } // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE // during multiplication. See the comments within the "sqrt" function. result = int256(PRBMath.sqrt(uint256(xy))); } } /// @notice Calculates 1 / x, rounding toward zero. /// /// @dev Requirements: /// - x cannot be zero. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the inverse. /// @return result The inverse as a signed 59.18-decimal fixed-point number. function inv(int256 x) internal pure returns (int256 result) { unchecked { // 1e36 is SCALE * SCALE. result = 1e36 / x; } } /// @notice Calculates the natural logarithm of x. /// /// @dev Based on the insight that ln(x) = log2(x) / log2(e). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// - This doesn't return exactly 1 for 2718281828459045235, for that we would need more fine-grained precision. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the natural logarithm. /// @return result The natural logarithm as a signed 59.18-decimal fixed-point number. function ln(int256 x) internal pure returns (int256 result) { // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x) // can return is 195205294292027477728. unchecked { result = (log2(x) * SCALE) / LOG2_E; } } /// @notice Calculates the common logarithm of x. /// /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common /// logarithm based on the insight that log10(x) = log2(x) / log2(10). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the common logarithm. /// @return result The common logarithm as a signed 59.18-decimal fixed-point number. function log10(int256 x) internal pure returns (int256 result) { if (x <= 0) { revert PRBMathSD59x18__LogInputTooSmall(x); } // Note that the "mul" in this block is the assembly mul operation, not the "mul" function defined in this contract. // prettier-ignore assembly { switch x case 1 { result := mul(SCALE, sub(0, 18)) } case 10 { result := mul(SCALE, sub(1, 18)) } case 100 { result := mul(SCALE, sub(2, 18)) } case 1000 { result := mul(SCALE, sub(3, 18)) } case 10000 { result := mul(SCALE, sub(4, 18)) } case 100000 { result := mul(SCALE, sub(5, 18)) } case 1000000 { result := mul(SCALE, sub(6, 18)) } case 10000000 { result := mul(SCALE, sub(7, 18)) } case 100000000 { result := mul(SCALE, sub(8, 18)) } case 1000000000 { result := mul(SCALE, sub(9, 18)) } case 10000000000 { result := mul(SCALE, sub(10, 18)) } case 100000000000 { result := mul(SCALE, sub(11, 18)) } case 1000000000000 { result := mul(SCALE, sub(12, 18)) } case 10000000000000 { result := mul(SCALE, sub(13, 18)) } case 100000000000000 { result := mul(SCALE, sub(14, 18)) } case 1000000000000000 { result := mul(SCALE, sub(15, 18)) } case 10000000000000000 { result := mul(SCALE, sub(16, 18)) } case 100000000000000000 { result := mul(SCALE, sub(17, 18)) } case 1000000000000000000 { result := 0 } case 10000000000000000000 { result := SCALE } case 100000000000000000000 { result := mul(SCALE, 2) } case 1000000000000000000000 { result := mul(SCALE, 3) } case 10000000000000000000000 { result := mul(SCALE, 4) } case 100000000000000000000000 { result := mul(SCALE, 5) } case 1000000000000000000000000 { result := mul(SCALE, 6) } case 10000000000000000000000000 { result := mul(SCALE, 7) } case 100000000000000000000000000 { result := mul(SCALE, 8) } case 1000000000000000000000000000 { result := mul(SCALE, 9) } case 10000000000000000000000000000 { result := mul(SCALE, 10) } case 100000000000000000000000000000 { result := mul(SCALE, 11) } case 1000000000000000000000000000000 { result := mul(SCALE, 12) } case 10000000000000000000000000000000 { result := mul(SCALE, 13) } case 100000000000000000000000000000000 { result := mul(SCALE, 14) } case 1000000000000000000000000000000000 { result := mul(SCALE, 15) } case 10000000000000000000000000000000000 { result := mul(SCALE, 16) } case 100000000000000000000000000000000000 { result := mul(SCALE, 17) } case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) } case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) } case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) } case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) } case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) } case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) } case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) } case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) } case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) } case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) } case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) } case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) } case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) } case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) } case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) } case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) } case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) } case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) } case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) } case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) } case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) } case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) } case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) } case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) } case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) } case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) } case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) } case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) } case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) } case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) } case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) } case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) } case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) } case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) } case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) } case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) } case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) } case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) } case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) } case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) } case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) } default { result := MAX_SD59x18 } } if (result == MAX_SD59x18) { // Do the fixed-point division inline to save gas. The denominator is log2(10). unchecked { result = (log2(x) * SCALE) / 3_321928094887362347; } } } /// @notice Calculates the binary logarithm of x. /// /// @dev Based on the iterative approximation algorithm. /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation /// /// Requirements: /// - x must be greater than zero. /// /// Caveats: /// - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the binary logarithm. /// @return result The binary logarithm as a signed 59.18-decimal fixed-point number. function log2(int256 x) internal pure returns (int256 result) { if (x <= 0) { revert PRBMathSD59x18__LogInputTooSmall(x); } unchecked { // This works because log2(x) = -log2(1/x). int256 sign; if (x >= SCALE) { sign = 1; } else { sign = -1; // Do the fixed-point inversion inline to save gas. The numerator is SCALE * SCALE. assembly { x := div(1000000000000000000000000000000000000, x) } } // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n). uint256 n = PRBMath.mostSignificantBit(uint256(x / SCALE)); // The integer part of the logarithm as a signed 59.18-decimal fixed-point number. The operation can't overflow // because n is maximum 255, SCALE is 1e18 and sign is either 1 or -1. result = int256(n) * SCALE; // This is y = x * 2^(-n). int256 y = x >> n; // If y = 1, the fractional part is zero. if (y == SCALE) { return result * sign; } // Calculate the fractional part via the iterative approximation. // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster. for (int256 delta = int256(HALF_SCALE); delta > 0; delta >>= 1) { y = (y * y) / SCALE; // Is y^2 > 2 and so in the range [2,4)? if (y >= 2 * SCALE) { // Add the 2^(-m) factor to the logarithm. result += delta; // Corresponds to z/2 on Wikipedia. y >>= 1; } } result *= sign; } } /// @notice Multiplies two signed 59.18-decimal fixed-point numbers together, returning a new signed 59.18-decimal /// fixed-point number. /// /// @dev Variant of "mulDiv" that works with signed numbers and employs constant folding, i.e. the denominator is /// always 1e18. /// /// Requirements: /// - All from "PRBMath.mulDivFixedPoint". /// - None of the inputs can be MIN_SD59x18 /// - The result must fit within MAX_SD59x18. /// /// Caveats: /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works. /// /// @param x The multiplicand as a signed 59.18-decimal fixed-point number. /// @param y The multiplier as a signed 59.18-decimal fixed-point number. /// @return result The product as a signed 59.18-decimal fixed-point number. function mul(int256 x, int256 y) internal pure returns (int256 result) { if (x == MIN_SD59x18 || y == MIN_SD59x18) { revert PRBMathSD59x18__MulInputTooSmall(); } unchecked { uint256 ax; uint256 ay; ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); uint256 rAbs = PRBMath.mulDivFixedPoint(ax, ay); if (rAbs > uint256(MAX_SD59x18)) { revert PRBMathSD59x18__MulOverflow(rAbs); } uint256 sx; uint256 sy; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) } result = sx ^ sy == 1 ? -int256(rAbs) : int256(rAbs); } } /// @notice Returns PI as a signed 59.18-decimal fixed-point number. function pi() internal pure returns (int256 result) { result = 3_141592653589793238; } /// @notice Raises x to the power of y. /// /// @dev Based on the insight that x^y = 2^(log2(x) * y). /// /// Requirements: /// - All from "exp2", "log2" and "mul". /// - z cannot be zero. /// /// Caveats: /// - All from "exp2", "log2" and "mul". /// - Assumes 0^0 is 1. /// /// @param x Number to raise to given power y, as a signed 59.18-decimal fixed-point number. /// @param y Exponent to raise x to, as a signed 59.18-decimal fixed-point number. /// @return result x raised to power y, as a signed 59.18-decimal fixed-point number. function pow(int256 x, int256 y) internal pure returns (int256 result) { if (x == 0) { result = y == 0 ? SCALE : int256(0); } else { result = exp2(mul(log2(x), y)); } } /// @notice Raises x (signed 59.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the /// famous algorithm "exponentiation by squaring". /// /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring /// /// Requirements: /// - All from "abs" and "PRBMath.mulDivFixedPoint". /// - The result must fit within MAX_SD59x18. /// /// Caveats: /// - All from "PRBMath.mulDivFixedPoint". /// - Assumes 0^0 is 1. /// /// @param x The base as a signed 59.18-decimal fixed-point number. /// @param y The exponent as an uint256. /// @return result The result as a signed 59.18-decimal fixed-point number. function powu(int256 x, uint256 y) internal pure returns (int256 result) { uint256 xAbs = uint256(abs(x)); // Calculate the first iteration of the loop in advance. uint256 rAbs = y & 1 > 0 ? xAbs : uint256(SCALE); // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster. uint256 yAux = y; for (yAux >>= 1; yAux > 0; yAux >>= 1) { xAbs = PRBMath.mulDivFixedPoint(xAbs, xAbs); // Equivalent to "y % 2 == 1" but faster. if (yAux & 1 > 0) { rAbs = PRBMath.mulDivFixedPoint(rAbs, xAbs); } } // The result must fit within the 59.18-decimal fixed-point representation. if (rAbs > uint256(MAX_SD59x18)) { revert PRBMathSD59x18__PowuOverflow(rAbs); } // Is the base negative and the exponent an odd number? bool isNegative = x < 0 && y & 1 == 1; result = isNegative ? -int256(rAbs) : int256(rAbs); } /// @notice Returns 1 as a signed 59.18-decimal fixed-point number. function scale() internal pure returns (int256 result) { result = SCALE; } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Requirements: /// - x cannot be negative. /// - x must be less than MAX_SD59x18 / SCALE. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the square root. /// @return result The result as a signed 59.18-decimal fixed-point . function sqrt(int256 x) internal pure returns (int256 result) { unchecked { if (x < 0) { revert PRBMathSD59x18__SqrtNegativeInput(x); } if (x > MAX_SD59x18 / SCALE) { revert PRBMathSD59x18__SqrtOverflow(x); } // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two signed // 59.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root). result = int256(PRBMath.sqrt(uint256(x * SCALE))); } } /// @notice Converts a signed 59.18-decimal fixed-point number to basic integer form, rounding down in the process. /// @param x The signed 59.18-decimal fixed-point number to convert. /// @return result The same number in basic integer form. function toInt(int256 x) internal pure returns (int256 result) { unchecked { result = x / SCALE; } } }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; import "./PRBMath.sol"; /// @title PRBMathUD60x18 /// @author Paul Razvan Berg /// @notice Smart contract library for advanced fixed-point math that works with uint256 numbers considered to have 18 /// trailing decimals. We call this number representation unsigned 60.18-decimal fixed-point, since there can be up to 60 /// digits in the integer part and up to 18 decimals in the fractional part. The numbers are bound by the minimum and the /// maximum values permitted by the Solidity type uint256. library PRBMathUD60x18 { /// @dev Half the SCALE number. uint256 internal constant HALF_SCALE = 5e17; /// @dev log2(e) as an unsigned 60.18-decimal fixed-point number. uint256 internal constant LOG2_E = 1_442695040888963407; /// @dev The maximum value an unsigned 60.18-decimal fixed-point number can have. uint256 internal constant MAX_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_584007913129639935; /// @dev The maximum whole value an unsigned 60.18-decimal fixed-point number can have. uint256 internal constant MAX_WHOLE_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_000000000000000000; /// @dev How many trailing decimals can be represented. uint256 internal constant SCALE = 1e18; /// @notice Calculates the arithmetic average of x and y, rounding down. /// @param x The first operand as an unsigned 60.18-decimal fixed-point number. /// @param y The second operand as an unsigned 60.18-decimal fixed-point number. /// @return result The arithmetic average as an unsigned 60.18-decimal fixed-point number. function avg(uint256 x, uint256 y) internal pure returns (uint256 result) { // The operations can never overflow. unchecked { // The last operand checks if both x and y are odd and if that is the case, we add 1 to the result. We need // to do this because if both numbers are odd, the 0.5 remainder gets truncated twice. result = (x >> 1) + (y >> 1) + (x & y & 1); } } /// @notice Yields the least unsigned 60.18 decimal fixed-point number greater than or equal to x. /// /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x must be less than or equal to MAX_WHOLE_UD60x18. /// /// @param x The unsigned 60.18-decimal fixed-point number to ceil. /// @param result The least integer greater than or equal to x, as an unsigned 60.18-decimal fixed-point number. function ceil(uint256 x) internal pure returns (uint256 result) { if (x > MAX_WHOLE_UD60x18) { revert PRBMathUD60x18__CeilOverflow(x); } assembly { // Equivalent to "x % SCALE" but faster. let remainder := mod(x, SCALE) // Equivalent to "SCALE - remainder" but faster. let delta := sub(SCALE, remainder) // Equivalent to "x + delta * (remainder > 0 ? 1 : 0)" but faster. result := add(x, mul(delta, gt(remainder, 0))) } } /// @notice Divides two unsigned 60.18-decimal fixed-point numbers, returning a new unsigned 60.18-decimal fixed-point number. /// /// @dev Uses mulDiv to enable overflow-safe multiplication and division. /// /// Requirements: /// - The denominator cannot be zero. /// /// @param x The numerator as an unsigned 60.18-decimal fixed-point number. /// @param y The denominator as an unsigned 60.18-decimal fixed-point number. /// @param result The quotient as an unsigned 60.18-decimal fixed-point number. function div(uint256 x, uint256 y) internal pure returns (uint256 result) { result = PRBMath.mulDiv(x, SCALE, y); } /// @notice Returns Euler's number as an unsigned 60.18-decimal fixed-point number. /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant). function e() internal pure returns (uint256 result) { result = 2_718281828459045235; } /// @notice Calculates the natural exponent of x. /// /// @dev Based on the insight that e^x = 2^(x * log2(e)). /// /// Requirements: /// - All from "log2". /// - x must be less than 133.084258667509499441. /// /// @param x The exponent as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function exp(uint256 x) internal pure returns (uint256 result) { // Without this check, the value passed to "exp2" would be greater than 192. if (x >= 133_084258667509499441) { revert PRBMathUD60x18__ExpInputTooBig(x); } // Do the fixed-point multiplication inline to save gas. unchecked { uint256 doubleScaleProduct = x * LOG2_E; result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// /// @dev See https://ethereum.stackexchange.com/q/79903/24693. /// /// Requirements: /// - x must be 192 or less. /// - The result must fit within MAX_UD60x18. /// /// @param x The exponent as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function exp2(uint256 x) internal pure returns (uint256 result) { // 2^192 doesn't fit within the 192.64-bit format used internally in this function. if (x >= 192e18) { revert PRBMathUD60x18__Exp2InputTooBig(x); } unchecked { // Convert x to the 192.64-bit fixed-point format. uint256 x192x64 = (x << 64) / SCALE; // Pass x to the PRBMath.exp2 function, which uses the 192.64-bit fixed-point number representation. result = PRBMath.exp2(x192x64); } } /// @notice Yields the greatest unsigned 60.18 decimal fixed-point number less than or equal to x. /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// @param x The unsigned 60.18-decimal fixed-point number to floor. /// @param result The greatest integer less than or equal to x, as an unsigned 60.18-decimal fixed-point number. function floor(uint256 x) internal pure returns (uint256 result) { assembly { // Equivalent to "x % SCALE" but faster. let remainder := mod(x, SCALE) // Equivalent to "x - remainder * (remainder > 0 ? 1 : 0)" but faster. result := sub(x, mul(remainder, gt(remainder, 0))) } } /// @notice Yields the excess beyond the floor of x. /// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part. /// @param x The unsigned 60.18-decimal fixed-point number to get the fractional part of. /// @param result The fractional part of x as an unsigned 60.18-decimal fixed-point number. function frac(uint256 x) internal pure returns (uint256 result) { assembly { result := mod(x, SCALE) } } /// @notice Converts a number from basic integer form to unsigned 60.18-decimal fixed-point representation. /// /// @dev Requirements: /// - x must be less than or equal to MAX_UD60x18 divided by SCALE. /// /// @param x The basic integer to convert. /// @param result The same number in unsigned 60.18-decimal fixed-point representation. function fromUint(uint256 x) internal pure returns (uint256 result) { unchecked { if (x > MAX_UD60x18 / SCALE) { revert PRBMathUD60x18__FromUintOverflow(x); } result = x * SCALE; } } /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down. /// /// @dev Requirements: /// - x * y must fit within MAX_UD60x18, lest it overflows. /// /// @param x The first operand as an unsigned 60.18-decimal fixed-point number. /// @param y The second operand as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function gm(uint256 x, uint256 y) internal pure returns (uint256 result) { if (x == 0) { return 0; } unchecked { // Checking for overflow this way is faster than letting Solidity do it. uint256 xy = x * y; if (xy / x != y) { revert PRBMathUD60x18__GmOverflow(x, y); } // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE // during multiplication. See the comments within the "sqrt" function. result = PRBMath.sqrt(xy); } } /// @notice Calculates 1 / x, rounding toward zero. /// /// @dev Requirements: /// - x cannot be zero. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the inverse. /// @return result The inverse as an unsigned 60.18-decimal fixed-point number. function inv(uint256 x) internal pure returns (uint256 result) { unchecked { // 1e36 is SCALE * SCALE. result = 1e36 / x; } } /// @notice Calculates the natural logarithm of x. /// /// @dev Based on the insight that ln(x) = log2(x) / log2(e). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// - This doesn't return exactly 1 for 2.718281828459045235, for that we would need more fine-grained precision. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the natural logarithm. /// @return result The natural logarithm as an unsigned 60.18-decimal fixed-point number. function ln(uint256 x) internal pure returns (uint256 result) { // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x) // can return is 196205294292027477728. unchecked { result = (log2(x) * SCALE) / LOG2_E; } } /// @notice Calculates the common logarithm of x. /// /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common /// logarithm based on the insight that log10(x) = log2(x) / log2(10). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the common logarithm. /// @return result The common logarithm as an unsigned 60.18-decimal fixed-point number. function log10(uint256 x) internal pure returns (uint256 result) { if (x < SCALE) { revert PRBMathUD60x18__LogInputTooSmall(x); } // Note that the "mul" in this block is the assembly multiplication operation, not the "mul" function defined // in this contract. // prettier-ignore assembly { switch x case 1 { result := mul(SCALE, sub(0, 18)) } case 10 { result := mul(SCALE, sub(1, 18)) } case 100 { result := mul(SCALE, sub(2, 18)) } case 1000 { result := mul(SCALE, sub(3, 18)) } case 10000 { result := mul(SCALE, sub(4, 18)) } case 100000 { result := mul(SCALE, sub(5, 18)) } case 1000000 { result := mul(SCALE, sub(6, 18)) } case 10000000 { result := mul(SCALE, sub(7, 18)) } case 100000000 { result := mul(SCALE, sub(8, 18)) } case 1000000000 { result := mul(SCALE, sub(9, 18)) } case 10000000000 { result := mul(SCALE, sub(10, 18)) } case 100000000000 { result := mul(SCALE, sub(11, 18)) } case 1000000000000 { result := mul(SCALE, sub(12, 18)) } case 10000000000000 { result := mul(SCALE, sub(13, 18)) } case 100000000000000 { result := mul(SCALE, sub(14, 18)) } case 1000000000000000 { result := mul(SCALE, sub(15, 18)) } case 10000000000000000 { result := mul(SCALE, sub(16, 18)) } case 100000000000000000 { result := mul(SCALE, sub(17, 18)) } case 1000000000000000000 { result := 0 } case 10000000000000000000 { result := SCALE } case 100000000000000000000 { result := mul(SCALE, 2) } case 1000000000000000000000 { result := mul(SCALE, 3) } case 10000000000000000000000 { result := mul(SCALE, 4) } case 100000000000000000000000 { result := mul(SCALE, 5) } case 1000000000000000000000000 { result := mul(SCALE, 6) } case 10000000000000000000000000 { result := mul(SCALE, 7) } case 100000000000000000000000000 { result := mul(SCALE, 8) } case 1000000000000000000000000000 { result := mul(SCALE, 9) } case 10000000000000000000000000000 { result := mul(SCALE, 10) } case 100000000000000000000000000000 { result := mul(SCALE, 11) } case 1000000000000000000000000000000 { result := mul(SCALE, 12) } case 10000000000000000000000000000000 { result := mul(SCALE, 13) } case 100000000000000000000000000000000 { result := mul(SCALE, 14) } case 1000000000000000000000000000000000 { result := mul(SCALE, 15) } case 10000000000000000000000000000000000 { result := mul(SCALE, 16) } case 100000000000000000000000000000000000 { result := mul(SCALE, 17) } case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) } case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) } case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) } case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) } case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) } case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) } case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) } case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) } case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) } case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) } case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) } case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) } case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) } case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) } case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) } case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) } case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) } case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) } case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) } case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) } case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) } case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) } case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) } case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) } case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) } case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) } case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) } case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) } case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) } case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) } case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) } case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) } case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) } case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) } case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) } case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) } case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) } case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) } case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) } case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) } case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) } case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 59) } default { result := MAX_UD60x18 } } if (result == MAX_UD60x18) { // Do the fixed-point division inline to save gas. The denominator is log2(10). unchecked { result = (log2(x) * SCALE) / 3_321928094887362347; } } } /// @notice Calculates the binary logarithm of x. /// /// @dev Based on the iterative approximation algorithm. /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation /// /// Requirements: /// - x must be greater than or equal to SCALE, otherwise the result would be negative. /// /// Caveats: /// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the binary logarithm. /// @return result The binary logarithm as an unsigned 60.18-decimal fixed-point number. function log2(uint256 x) internal pure returns (uint256 result) { if (x < SCALE) { revert PRBMathUD60x18__LogInputTooSmall(x); } unchecked { // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n). uint256 n = PRBMath.mostSignificantBit(x / SCALE); // The integer part of the logarithm as an unsigned 60.18-decimal fixed-point number. The operation can't overflow // because n is maximum 255 and SCALE is 1e18. result = n * SCALE; // This is y = x * 2^(-n). uint256 y = x >> n; // If y = 1, the fractional part is zero. if (y == SCALE) { return result; } // Calculate the fractional part via the iterative approximation. // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster. for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) { y = (y * y) / SCALE; // Is y^2 > 2 and so in the range [2,4)? if (y >= 2 * SCALE) { // Add the 2^(-m) factor to the logarithm. result += delta; // Corresponds to z/2 on Wikipedia. y >>= 1; } } } } /// @notice Multiplies two unsigned 60.18-decimal fixed-point numbers together, returning a new unsigned 60.18-decimal /// fixed-point number. /// @dev See the documentation for the "PRBMath.mulDivFixedPoint" function. /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The product as an unsigned 60.18-decimal fixed-point number. function mul(uint256 x, uint256 y) internal pure returns (uint256 result) { result = PRBMath.mulDivFixedPoint(x, y); } /// @notice Returns PI as an unsigned 60.18-decimal fixed-point number. function pi() internal pure returns (uint256 result) { result = 3_141592653589793238; } /// @notice Raises x to the power of y. /// /// @dev Based on the insight that x^y = 2^(log2(x) * y). /// /// Requirements: /// - All from "exp2", "log2" and "mul". /// /// Caveats: /// - All from "exp2", "log2" and "mul". /// - Assumes 0^0 is 1. /// /// @param x Number to raise to given power y, as an unsigned 60.18-decimal fixed-point number. /// @param y Exponent to raise x to, as an unsigned 60.18-decimal fixed-point number. /// @return result x raised to power y, as an unsigned 60.18-decimal fixed-point number. function pow(uint256 x, uint256 y) internal pure returns (uint256 result) { if (x == 0) { result = y == 0 ? SCALE : uint256(0); } else { result = exp2(mul(log2(x), y)); } } /// @notice Raises x (unsigned 60.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the /// famous algorithm "exponentiation by squaring". /// /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring /// /// Requirements: /// - The result must fit within MAX_UD60x18. /// /// Caveats: /// - All from "mul". /// - Assumes 0^0 is 1. /// /// @param x The base as an unsigned 60.18-decimal fixed-point number. /// @param y The exponent as an uint256. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function powu(uint256 x, uint256 y) internal pure returns (uint256 result) { // Calculate the first iteration of the loop in advance. result = y & 1 > 0 ? x : SCALE; // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster. for (y >>= 1; y > 0; y >>= 1) { x = PRBMath.mulDivFixedPoint(x, x); // Equivalent to "y % 2 == 1" but faster. if (y & 1 > 0) { result = PRBMath.mulDivFixedPoint(result, x); } } } /// @notice Returns 1 as an unsigned 60.18-decimal fixed-point number. function scale() internal pure returns (uint256 result) { result = SCALE; } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Requirements: /// - x must be less than MAX_UD60x18 / SCALE. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the square root. /// @return result The result as an unsigned 60.18-decimal fixed-point . function sqrt(uint256 x) internal pure returns (uint256 result) { unchecked { if (x > MAX_UD60x18 / SCALE) { revert PRBMathUD60x18__SqrtOverflow(x); } // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two unsigned // 60.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root). result = PRBMath.sqrt(x * SCALE); } } /// @notice Converts a unsigned 60.18-decimal fixed-point number to basic integer form, rounding down in the process. /// @param x The unsigned 60.18-decimal fixed-point number to convert. /// @return result The same number in basic integer form. function toUint(uint256 x) internal pure returns (uint256 result) { unchecked { result = x / SCALE; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Pool State */ interface IPoolState { /** * @notice Returns details of an auction for a given borrower address. * @param borrower_ Address of the borrower that is liquidated. * @return kicker_ Address of the kicker that is kicking the auction. * @return bondFactor_ The factor used for calculating bond size. * @return bondSize_ The bond amount in quote token terms. * @return kickTime_ Time the liquidation was initiated. * @return referencePrice_ Price used to determine auction start price. * @return neutralPrice_ `Neutral Price` of auction. * @return debtToCollateral_ Borrower debt to collateral, which is used in BPF for kicker's reward calculation. * @return head_ Address of the head auction. * @return next_ Address of the next auction in queue. * @return prev_ Address of the prev auction in queue. */ function auctionInfo(address borrower_) external view returns ( address kicker_, uint256 bondFactor_, uint256 bondSize_, uint256 kickTime_, uint256 referencePrice_, uint256 neutralPrice_, uint256 debtToCollateral_, address head_, address next_, address prev_ ); /** * @notice Returns pool related debt values. * @return debt_ Current amount of debt owed by borrowers in pool. * @return accruedDebt_ Debt owed by borrowers based on last inflator snapshot. * @return debtInAuction_ Total amount of debt in auction. * @return t0Debt2ToCollateral_ t0debt accross all borrowers divided by their collateral, used in determining a collateralization weighted debt. */ function debtInfo() external view returns ( uint256 debt_, uint256 accruedDebt_, uint256 debtInAuction_, uint256 t0Debt2ToCollateral_ ); /** * @notice Mapping of borrower addresses to `Borrower` structs. * @dev NOTE: Cannot use appended underscore syntax for return params since struct is used. * @param borrower_ Address of the borrower. * @return t0Debt_ Amount of debt borrower would have had if their loan was the first debt drawn from the pool. * @return collateral_ Amount of collateral that the borrower has deposited, in collateral token. * @return npTpRatio_ Np to Tp ratio of borrower at the time of last borrow or pull collateral. */ function borrowerInfo(address borrower_) external view returns ( uint256 t0Debt_, uint256 collateral_, uint256 npTpRatio_ ); /** * @notice Mapping of buckets indexes to `Bucket` structs. * @dev NOTE: Cannot use appended underscore syntax for return params since struct is used. * @param index_ Bucket index. * @return lpAccumulator_ Amount of `LP` accumulated in current bucket. * @return availableCollateral_ Amount of collateral available in current bucket. * @return bankruptcyTime_ Timestamp when bucket become insolvent, `0` if healthy. * @return bucketDeposit_ Amount of quote tokens in bucket. * @return bucketScale_ Bucket multiplier. */ function bucketInfo(uint256 index_) external view returns ( uint256 lpAccumulator_, uint256 availableCollateral_, uint256 bankruptcyTime_, uint256 bucketDeposit_, uint256 bucketScale_ ); /** * @notice Mapping of burnEventEpoch to `BurnEvent` structs. * @dev Reserve auctions correspond to burn events. * @param burnEventEpoch_ Id of the current reserve auction. * @return burnBlock_ Block in which a reserve auction started. * @return totalInterest_ Total interest as of the reserve auction. * @return totalBurned_ Total ajna tokens burned as of the reserve auction. */ function burnInfo(uint256 burnEventEpoch_) external view returns (uint256, uint256, uint256); /** * @notice Returns the latest `burnEventEpoch` of reserve auctions. * @dev If a reserve auction is active, it refers to the current reserve auction. If no reserve auction is active, it refers to the last reserve auction. * @return Current `burnEventEpoch`. */ function currentBurnEpoch() external view returns (uint256); /** * @notice Returns information about the pool `EMA (Exponential Moving Average)` variables. * @return debtColEma_ Debt squared to collateral Exponential, numerator to `TU` calculation. * @return lupt0DebtEma_ Exponential of `LUP * t0 debt`, denominator to `TU` calculation * @return debtEma_ Exponential debt moving average. * @return depositEma_ sample of meaningful deposit Exponential, denominator to `MAU` calculation. */ function emasInfo() external view returns ( uint256 debtColEma_, uint256 lupt0DebtEma_, uint256 debtEma_, uint256 depositEma_ ); /** * @notice Returns information about pool inflator. * @return inflator_ Pool inflator value. * @return lastUpdate_ The timestamp of the last `inflator` update. */ function inflatorInfo() external view returns ( uint256 inflator_, uint256 lastUpdate_ ); /** * @notice Returns information about pool interest rate. * @return interestRate_ Current interest rate in pool. * @return interestRateUpdate_ The timestamp of the last interest rate update. */ function interestRateInfo() external view returns ( uint256 interestRate_, uint256 interestRateUpdate_ ); /** * @notice Returns details about kicker balances. * @param kicker_ The address of the kicker to retrieved info for. * @return claimable_ Amount of quote token kicker can claim / withdraw from pool at any time. * @return locked_ Amount of quote token kicker locked in auctions (as bonds). */ function kickerInfo(address kicker_) external view returns ( uint256 claimable_, uint256 locked_ ); /** * @notice Mapping of buckets indexes and owner addresses to `Lender` structs. * @param index_ Bucket index. * @param lender_ Address of the liquidity provider. * @return lpBalance_ Amount of `LP` owner has in current bucket. * @return depositTime_ Time the user last deposited quote token. */ function lenderInfo( uint256 index_, address lender_ ) external view returns ( uint256 lpBalance_, uint256 depositTime_ ); /** * @notice Return the `LP` allowance a `LP` owner provided to a spender. * @param index_ Bucket index. * @param spender_ Address of the `LP` spender. * @param owner_ The initial owner of the `LP`. * @return allowance_ Amount of `LP` spender can utilize. */ function lpAllowance( uint256 index_, address spender_, address owner_ ) external view returns (uint256 allowance_); /** * @notice Returns information about a loan in the pool. * @param loanId_ Loan's id within loan heap. Max loan is position `1`. * @return borrower_ Borrower address at the given position. * @return t0DebtToCollateral_ Borrower t0 debt to collateral. */ function loanInfo( uint256 loanId_ ) external view returns ( address borrower_, uint256 t0DebtToCollateral_ ); /** * @notice Returns information about pool loans. * @return maxBorrower_ Borrower address with highest t0 debt to collateral. * @return maxT0DebtToCollateral_ Highest t0 debt to collateral in pool. * @return noOfLoans_ Total number of loans. */ function loansInfo() external view returns ( address maxBorrower_, uint256 maxT0DebtToCollateral_, uint256 noOfLoans_ ); /** * @notice Returns information about pool reserves. * @return liquidationBondEscrowed_ Amount of liquidation bond across all liquidators. * @return reserveAuctionUnclaimed_ Amount of claimable reserves which has not been taken in the `Claimable Reserve Auction`. * @return reserveAuctionKicked_ Time a `Claimable Reserve Auction` was last kicked. * @return lastKickedReserves_ Amount of reserves upon last kick, used to calculate price. * @return totalInterestEarned_ Total interest earned by all lenders in the pool */ function reservesInfo() external view returns ( uint256 liquidationBondEscrowed_, uint256 reserveAuctionUnclaimed_, uint256 reserveAuctionKicked_, uint256 lastKickedReserves_, uint256 totalInterestEarned_ ); /** * @notice Returns the `pledgedCollateral` state variable. * @return The total pledged collateral in the system, in WAD units. */ function pledgedCollateral() external view returns (uint256); /** * @notice Returns the total number of active auctions in pool. * @return totalAuctions_ Number of active auctions. */ function totalAuctionsInPool() external view returns (uint256); /** * @notice Returns the `t0Debt` state variable. * @dev This value should be multiplied by inflator in order to calculate current debt of the pool. * @return The total `t0Debt` in the system, in `WAD` units. */ function totalT0Debt() external view returns (uint256); /** * @notice Returns the `t0DebtInAuction` state variable. * @dev This value should be multiplied by inflator in order to calculate current debt in auction of the pool. * @return The total `t0DebtInAuction` in the system, in `WAD` units. */ function totalT0DebtInAuction() external view returns (uint256); /** * @notice Mapping of addresses that can transfer `LP` to a given lender. * @param lender_ Lender that receives `LP`. * @param transferor_ Transferor that transfers `LP`. * @return True if the transferor is approved by lender. */ function approvedTransferors( address lender_, address transferor_ ) external view returns (bool); } /*********************/ /*** State Structs ***/ /*********************/ /******************/ /*** Pool State ***/ /******************/ /// @dev Struct holding inflator state. struct InflatorState { uint208 inflator; // [WAD] pool's inflator uint48 inflatorUpdate; // [SEC] last time pool's inflator was updated } /// @dev Struct holding pool interest state. struct InterestState { uint208 interestRate; // [WAD] pool's interest rate uint48 interestRateUpdate; // [SEC] last time pool's interest rate was updated (not before 12 hours passed) uint256 debt; // [WAD] previous update's debt uint256 meaningfulDeposit; // [WAD] previous update's meaningfulDeposit uint256 t0Debt2ToCollateral; // [WAD] utilization weight accumulator, tracks debt and collateral relationship accross borrowers uint256 debtCol; // [WAD] previous debt squared to collateral uint256 lupt0Debt; // [WAD] previous LUP * t0 debt } /// @dev Struct holding pool EMAs state. struct EmaState { uint256 debtEma; // [WAD] sample of debt EMA, numerator to MAU calculation uint256 depositEma; // [WAD] sample of meaningful deposit EMA, denominator to MAU calculation uint256 debtColEma; // [WAD] debt squared to collateral EMA, numerator to TU calculation uint256 lupt0DebtEma; // [WAD] EMA of LUP * t0 debt, denominator to TU calculation uint256 emaUpdate; // [SEC] last time pool's EMAs were updated } /// @dev Struct holding pool balances state. struct PoolBalancesState { uint256 pledgedCollateral; // [WAD] total collateral pledged in pool uint256 t0DebtInAuction; // [WAD] Total debt in auction used to restrict LPB holder from withdrawing uint256 t0Debt; // [WAD] Pool debt as if the whole amount was incurred upon the first loan } /// @dev Struct holding pool params (in memory only). struct PoolState { uint8 poolType; // pool type, can be ERC20 or ERC721 uint256 t0Debt; // [WAD] t0 debt in pool uint256 t0DebtInAuction; // [WAD] t0 debt in auction within pool uint256 debt; // [WAD] total debt in pool, accrued in current block uint256 collateral; // [WAD] total collateral pledged in pool uint256 inflator; // [WAD] current pool inflator bool isNewInterestAccrued; // true if new interest already accrued in current block uint256 rate; // [WAD] pool's current interest rate uint256 quoteTokenScale; // [WAD] quote token scale of the pool. Same as quote token dust. } /*********************/ /*** Buckets State ***/ /*********************/ /// @dev Struct holding lender state. struct Lender { uint256 lps; // [WAD] Lender LP accumulator uint256 depositTime; // timestamp of last deposit } /// @dev Struct holding bucket state. struct Bucket { uint256 lps; // [WAD] Bucket LP accumulator uint256 collateral; // [WAD] Available collateral tokens deposited in the bucket uint256 bankruptcyTime; // Timestamp when bucket become insolvent, 0 if healthy mapping(address => Lender) lenders; // lender address to Lender struct mapping } /**********************/ /*** Deposits State ***/ /**********************/ /// @dev Struct holding deposits (Fenwick) values and scaling. struct DepositsState { uint256[8193] values; // Array of values in the FenwickTree. uint256[8193] scaling; // Array of values which scale (multiply) the FenwickTree accross indexes. } /*******************/ /*** Loans State ***/ /*******************/ /// @dev Struct holding loans state. struct LoansState { Loan[] loans; mapping (address => uint) indices; // borrower address => loan index mapping mapping (address => Borrower) borrowers; // borrower address => Borrower struct mapping } /// @dev Struct holding loan state. struct Loan { address borrower; // borrower address uint96 t0DebtToCollateral; // [WAD] Borrower t0 debt to collateral. } /// @dev Struct holding borrower state. struct Borrower { uint256 t0Debt; // [WAD] Borrower debt time-adjusted as if it was incurred upon first loan of pool. uint256 collateral; // [WAD] Collateral deposited by borrower. uint256 npTpRatio; // [WAD] Np to Tp ratio at the time of last borrow or pull collateral. } /**********************/ /*** Auctions State ***/ /**********************/ /// @dev Struct holding pool auctions state. struct AuctionsState { uint96 noOfAuctions; // total number of auctions in pool address head; // first address in auction queue address tail; // last address in auction queue uint256 totalBondEscrowed; // [WAD] total amount of quote token posted as auction kick bonds mapping(address => Liquidation) liquidations; // mapping of borrower address and auction details mapping(address => Kicker) kickers; // mapping of kicker address and kicker balances } /// @dev Struct holding liquidation state. struct Liquidation { address kicker; // address that initiated liquidation uint96 bondFactor; // [WAD] bond factor used to start liquidation uint96 kickTime; // timestamp when liquidation was started address prev; // previous liquidated borrower in auctions queue uint96 referencePrice; // [WAD] used to calculate auction start price address next; // next liquidated borrower in auctions queue uint160 bondSize; // [WAD] liquidation bond size uint96 neutralPrice; // [WAD] Neutral Price when liquidation was started uint256 debtToCollateral; // [WAD] Borrower debt to collateral, which is used in BPF for kicker's reward calculation uint256 t0ReserveSettleAmount; // [WAD] Amount of t0Debt that could be settled via reserves in this auction } /// @dev Struct holding kicker state. struct Kicker { uint256 claimable; // [WAD] kicker's claimable balance uint256 locked; // [WAD] kicker's balance of tokens locked in auction bonds } /******************************/ /*** Reserve Auctions State ***/ /******************************/ /// @dev Struct holding reserve auction state. struct ReserveAuctionState { uint256 kicked; // Time a Claimable Reserve Auction was last kicked. uint256 lastKickedReserves; // [WAD] Amount of reserves upon last kick, used to calculate price. uint256 unclaimed; // [WAD] Amount of claimable reserves which has not been taken in the Claimable Reserve Auction. uint256 latestBurnEventEpoch; // Latest burn event epoch. uint256 totalAjnaBurned; // [WAD] Total ajna burned in the pool. uint256 totalInterestEarned; // [WAD] Total interest earned by all lenders in the pool. mapping (uint256 => BurnEvent) burnEvents; // Mapping burnEventEpoch => BurnEvent. } /// @dev Struct holding burn event state. struct BurnEvent { uint256 timestamp; // time at which the burn event occured uint256 totalInterest; // [WAD] current pool interest accumulator `PoolCommons.accrueInterest().newInterest` uint256 totalBurned; // [WAD] burn amount accumulator }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; interface IERC3156FlashBorrower { /** * @dev Receive a flash loan. * @param initiator The initiator of the loan. * @param token The loan currency. * @param amount The amount of tokens lent (token precision). * @param fee The additional amount of tokens to repay. * @param data Arbitrary data structure, intended to contain user-defined parameters. * @return The `keccak256` hash of `ERC3156FlashBorrower.onFlashLoan` */ function onFlashLoan( address initiator, address token, uint256 amount, uint256 fee, bytes calldata data ) external returns (bytes32); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import { PRBMathSD59x18 } from "@prb-math/contracts/PRBMathSD59x18.sol"; import { Math } from '@openzeppelin/contracts/utils/math/Math.sol'; import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import { PoolType } from '../../interfaces/pool/IPool.sol'; import { InflatorState, PoolState } from '../../interfaces/pool/commons/IPoolState.sol'; import { Buckets } from '../internal/Buckets.sol'; import { Maths } from '../internal/Maths.sol'; error BucketIndexOutOfBounds(); error BucketPriceOutOfBounds(); /*************************/ /*** Price Conversions ***/ /*************************/ /// @dev constant price indices defining the min and max of the potential price range int256 constant MAX_BUCKET_INDEX = 4_156; int256 constant MIN_BUCKET_INDEX = -3_232; uint256 constant MAX_FENWICK_INDEX = 7_388; uint256 constant MIN_PRICE = 99_836_282_890; uint256 constant MAX_PRICE = 1_004_968_987.606512354182109771 * 1e18; uint256 constant MAX_INFLATED_PRICE = 50_248_449_380.325617709105488550 * 1e18; // 50 * MAX_PRICE /// @dev deposit buffer (extra margin) used for calculating reserves uint256 constant DEPOSIT_BUFFER = 1.000000001 * 1e18; /// @dev step amounts in basis points. This is a constant across pools at `0.005`, achieved by dividing `WAD` by `10,000` int256 constant FLOAT_STEP_INT = 1.005 * 1e18; /// @dev collateralization factor used to calculate borrrower HTP/TP/collateralization. uint256 constant COLLATERALIZATION_FACTOR = 1.04 * 1e18; /** * @notice Calculates the price (`WAD` precision) for a given `Fenwick` index. * @dev Reverts with `BucketIndexOutOfBounds` if index exceeds maximum constant. * @dev Uses fixed-point math to get around lack of floating point numbers in `EVM`. * @dev Fenwick index is converted to bucket index. * @dev Fenwick index to bucket index conversion: * @dev `1.00` : bucket index `0`, fenwick index `4156`: `7388-4156-3232=0`. * @dev `MAX_PRICE` : bucket index `4156`, fenwick index `0`: `7388-0-3232=4156`. * @dev `MIN_PRICE` : bucket index - `3232`, fenwick index `7388`: `7388-7388-3232=-3232`. * @dev `V1`: `price = MIN_PRICE + (FLOAT_STEP * index)` * @dev `V2`: `price = MAX_PRICE * (FLOAT_STEP ** (abs(int256(index - MAX_PRICE_INDEX))));` * @dev `V3 (final)`: `x^y = 2^(y*log_2(x))` */ function _priceAt( uint256 index_ ) pure returns (uint256) { // Lowest Fenwick index is highest price, so invert the index and offset by highest bucket index. int256 bucketIndex = MAX_BUCKET_INDEX - int256(index_); if (bucketIndex < MIN_BUCKET_INDEX || bucketIndex > MAX_BUCKET_INDEX) revert BucketIndexOutOfBounds(); return uint256( PRBMathSD59x18.exp2( PRBMathSD59x18.mul( PRBMathSD59x18.fromInt(bucketIndex), PRBMathSD59x18.log2(FLOAT_STEP_INT) ) ) ); } /** * @notice Calculates the Fenwick index for a given price. * @dev Reverts with `BucketPriceOutOfBounds` if price exceeds maximum constant. * @dev Price expected to be inputted as a `WAD` (`18` decimal). * @dev `V1`: `bucket index = (price - MIN_PRICE) / FLOAT_STEP` * @dev `V2`: `bucket index = (log(FLOAT_STEP) * price) / MAX_PRICE` * @dev `V3 (final)`: `bucket index = log_2(price) / log_2(FLOAT_STEP)` * @dev `Fenwick index = 7388 - bucket index + 3232` */ function _indexOf( uint256 price_ ) pure returns (uint256) { if (price_ < MIN_PRICE || price_ > MAX_PRICE) revert BucketPriceOutOfBounds(); int256 index = PRBMathSD59x18.div( PRBMathSD59x18.log2(int256(price_)), PRBMathSD59x18.log2(FLOAT_STEP_INT) ); int256 ceilIndex = PRBMathSD59x18.ceil(index); if (index < 0 && ceilIndex - index > 0.5 * 1e18) { return uint256(4157 - PRBMathSD59x18.toInt(ceilIndex)); } return uint256(4156 - PRBMathSD59x18.toInt(ceilIndex)); } /**********************/ /*** Pool Utilities ***/ /**********************/ /** * @notice Calculates the minimum debt amount that can be borrowed or can remain in a loan in pool. * @param debt_ The debt amount to calculate minimum debt amount for. * @param loansCount_ The number of loans in pool. * @return minDebtAmount_ Minimum debt amount value of the pool. */ function _minDebtAmount( uint256 debt_, uint256 loansCount_ ) pure returns (uint256 minDebtAmount_) { if (loansCount_ != 0) { minDebtAmount_ = Maths.wdiv(Maths.wdiv(debt_, Maths.wad(loansCount_)), 10**19); } } /** * @notice Calculates origination fee for a given interest rate. * @notice Calculated as greater of the current annualized interest rate divided by `52` (one week of interest) or `5` bps. * @param interestRate_ The current interest rate. * @return Fee rate based upon the given interest rate. */ function _borrowFeeRate( uint256 interestRate_ ) pure returns (uint256) { // greater of the current annualized interest rate divided by 52 (one week of interest) or 5 bps return Maths.max(Maths.wdiv(interestRate_, 52 * 1e18), 0.0005 * 1e18); } /** * @notice Calculates the unutilized deposit fee, charged to lenders who deposit below the `LUP`. * @param interestRate_ The current interest rate. * @return Fee rate based upon the given interest rate */ function _depositFeeRate( uint256 interestRate_ ) pure returns (uint256) { // current annualized rate divided by 365 * 3 (8 hours of interest) return Maths.wdiv(interestRate_, 365 * 3e18); } /** * @notice Determines how the inflator state should be updated * @param poolState_ State of the pool after updateInterestState was called. * @param inflatorState_ Old inflator state. * @return newInflator_ New inflator value. * @return updateTimestamp_ `True` if timestamp of last update should be updated. */ function _determineInflatorState( PoolState memory poolState_, InflatorState memory inflatorState_ ) view returns (uint208 newInflator_, bool updateTimestamp_) { newInflator_ = inflatorState_.inflator; // update pool inflator if (poolState_.isNewInterestAccrued) { newInflator_ = SafeCast.toUint208(poolState_.inflator); updateTimestamp_ = true; // if the debt in the current pool state is 0, also update the inflator and inflatorUpdate fields in inflatorState // slither-disable-next-line incorrect-equality } else if (poolState_.debt == 0) { newInflator_ = SafeCast.toUint208(Maths.WAD); updateTimestamp_ = true; // if the first loan has just been drawn, update the inflator timestamp // slither-disable-next-line incorrect-equality } else if (inflatorState_.inflator == Maths.WAD && inflatorState_.inflatorUpdate != block.timestamp){ updateTimestamp_ = true; } } /** * @notice Calculates `HTP` price. * @param maxT0DebtToCollateral_ Max t0 debt to collateral in pool. * @param inflator_ Pool's inflator. */ function _htp( uint256 maxT0DebtToCollateral_, uint256 inflator_ ) pure returns (uint256) { return Maths.wmul( Maths.wmul(maxT0DebtToCollateral_, inflator_), COLLATERALIZATION_FACTOR ); } /** * @notice Calculates debt-weighted average threshold price. * @param t0Debt_ Pool debt owed by borrowers in `t0` terms. * @param inflator_ Pool's borrower inflator. * @param t0Debt2ToCollateral_ `t0-debt-squared-to-collateral` accumulator. */ function _dwatp( uint256 t0Debt_, uint256 inflator_, uint256 t0Debt2ToCollateral_ ) pure returns (uint256) { return t0Debt_ == 0 ? 0 : Maths.wdiv( Maths.wmul( Maths.wmul(inflator_, t0Debt2ToCollateral_), COLLATERALIZATION_FACTOR ), t0Debt_ ); } /** * @notice Collateralization calculation. * @param debt_ Debt to calculate collateralization for. * @param collateral_ Collateral to calculate collateralization for. * @param price_ Price to calculate collateralization for. * @param type_ Type of the pool. * @return `True` if value of collateral exceeds or equals debt. */ function _isCollateralized( uint256 debt_, uint256 collateral_, uint256 price_, uint8 type_ ) pure returns (bool) { // `False` if LUP = MIN_PRICE unless there is no debt if (price_ == MIN_PRICE && debt_ != 0) return false; // Use collateral floor for NFT pools if (type_ == uint8(PoolType.ERC721)) { //slither-disable-next-line divide-before-multiply collateral_ = (collateral_ / Maths.WAD) * Maths.WAD; // use collateral floor } return Maths.wmul(collateral_, price_) >= Maths.wmul(COLLATERALIZATION_FACTOR, debt_); } /** * @notice Price precision adjustment used in calculating collateral dust for a bucket. * To ensure the accuracy of the exchange rate calculation, buckets with smaller prices require * larger minimum amounts of collateral. This formula imposes a lower bound independent of token scale. * @param bucketIndex_ Index of the bucket, or `0` for encumbered collateral with no bucket affinity. * @return pricePrecisionAdjustment_ Unscaled integer of the minimum number of decimal places the dust limit requires. */ function _getCollateralDustPricePrecisionAdjustment( uint256 bucketIndex_ ) pure returns (uint256 pricePrecisionAdjustment_) { // conditional is a gas optimization if (bucketIndex_ > 3900) { int256 bucketOffset = int256(bucketIndex_ - 3900); int256 result = PRBMathSD59x18.sqrt(PRBMathSD59x18.div(bucketOffset * 1e18, int256(36 * 1e18))); pricePrecisionAdjustment_ = uint256(result / 1e18); } } /** * @notice Returns the amount of collateral calculated for the given amount of `LP`. * @dev The value returned is capped at collateral amount available in bucket. * @param bucketCollateral_ Amount of collateral in bucket. * @param bucketLP_ Amount of `LP` in bucket. * @param deposit_ Current bucket deposit (quote tokens). Used to calculate bucket's exchange rate / `LP`. * @param lenderLPBalance_ The amount of `LP` to calculate collateral for. * @param bucketPrice_ Bucket's price. * @return collateralAmount_ Amount of collateral calculated for the given `LP `amount. */ function _lpToCollateral( uint256 bucketCollateral_, uint256 bucketLP_, uint256 deposit_, uint256 lenderLPBalance_, uint256 bucketPrice_ ) pure returns (uint256 collateralAmount_) { collateralAmount_ = Buckets.lpToCollateral( bucketCollateral_, bucketLP_, deposit_, lenderLPBalance_, bucketPrice_, Math.Rounding.Down ); if (collateralAmount_ > bucketCollateral_) { // user is owed more collateral than is available in the bucket collateralAmount_ = bucketCollateral_; } } /** * @notice Returns the amount of quote tokens calculated for the given amount of `LP`. * @dev The value returned is capped at available bucket deposit. * @param bucketLP_ Amount of `LP` in bucket. * @param bucketCollateral_ Amount of collateral in bucket. * @param deposit_ Current bucket deposit (quote tokens). Used to calculate bucket's exchange rate / `LP`. * @param lenderLPBalance_ The amount of `LP` to calculate quote token amount for. * @param bucketPrice_ Bucket's price. * @return quoteTokenAmount_ Amount of quote tokens calculated for the given `LP` amount, capped at available bucket deposit. */ function _lpToQuoteToken( uint256 bucketLP_, uint256 bucketCollateral_, uint256 deposit_, uint256 lenderLPBalance_, uint256 bucketPrice_ ) pure returns (uint256 quoteTokenAmount_) { quoteTokenAmount_ = Buckets.lpToQuoteTokens( bucketCollateral_, bucketLP_, deposit_, lenderLPBalance_, bucketPrice_, Math.Rounding.Down ); if (quoteTokenAmount_ > deposit_) quoteTokenAmount_ = deposit_; } /** * @notice Rounds a token amount down to the minimum amount permissible by the token scale. * @param amount_ Value to be rounded. * @param tokenScale_ Scale of the token, presented as a power of `10`. * @return scaledAmount_ Rounded value. */ function _roundToScale( uint256 amount_, uint256 tokenScale_ ) pure returns (uint256 scaledAmount_) { scaledAmount_ = (amount_ / tokenScale_) * tokenScale_; } /** * @notice Rounds a token amount up to the next amount permissible by the token scale. * @param amount_ Value to be rounded. * @param tokenScale_ Scale of the token, presented as a power of `10`. * @return scaledAmount_ Rounded value. */ function _roundUpToScale( uint256 amount_, uint256 tokenScale_ ) pure returns (uint256 scaledAmount_) { if (amount_ % tokenScale_ == 0) scaledAmount_ = amount_; else scaledAmount_ = _roundToScale(amount_, tokenScale_) + tokenScale_; } /*********************************/ /*** Reserve Auction Utilities ***/ /*********************************/ uint256 constant MINUTE_HALF_LIFE = 0.988514020352896135_356867505 * 1e27; // 0.5^(1/60) /** * @notice Calculates claimable reserves within the pool. * @dev Claimable reserve auctions and escrowed auction bonds are guaranteed by the pool. * @param debt_ Pool's debt. * @param poolSize_ Pool's deposit size. * @param totalBondEscrowed_ Total bond escrowed. * @param reserveAuctionUnclaimed_ Pool's unclaimed reserve auction. * @param quoteTokenBalance_ Pool's quote token balance. * @return claimable_ Calculated pool reserves. */ function _claimableReserves( uint256 debt_, uint256 poolSize_, uint256 totalBondEscrowed_, uint256 reserveAuctionUnclaimed_, uint256 quoteTokenBalance_ ) pure returns (uint256 claimable_) { uint256 guaranteedFunds = totalBondEscrowed_ + reserveAuctionUnclaimed_; // calculate claimable reserves if there's quote token excess if (quoteTokenBalance_ > guaranteedFunds) { claimable_ = debt_ + quoteTokenBalance_; claimable_ -= Maths.min( claimable_, // require 1.0 + 1e-9 deposit buffer (extra margin) for deposits Maths.wmul(DEPOSIT_BUFFER, poolSize_) + guaranteedFunds ); // incremental claimable reserve should not exceed excess quote in pool claimable_ = Maths.min( claimable_, quoteTokenBalance_ - guaranteedFunds ); } } /** * @notice Calculates reserves auction price. * @param reserveAuctionKicked_ Time when reserve auction was started (kicked). * @param lastKickedReserves_ Reserves to be auctioned when started (kicked). * @return price_ Calculated auction price. */ function _reserveAuctionPrice( uint256 reserveAuctionKicked_, uint256 lastKickedReserves_ ) view returns (uint256 price_) { if (reserveAuctionKicked_ != 0) { uint256 secondsElapsed = block.timestamp - reserveAuctionKicked_; uint256 hoursComponent = 1e27 >> secondsElapsed / 3600; uint256 minutesComponent = Maths.rpow(MINUTE_HALF_LIFE, secondsElapsed % 3600 / 60); uint256 initialPrice = lastKickedReserves_ == 0 ? 0 : Maths.wdiv(1_000_000_000 * 1e18, lastKickedReserves_); price_ = initialPrice * Maths.rmul(hoursComponent, minutesComponent) / 1e27; } } /*************************/ /*** Auction Utilities ***/ /*************************/ /// @dev min bond factor. uint256 constant MIN_BOND_FACTOR = 0.005 * 1e18; /// @dev max bond factor. uint256 constant MAX_BOND_FACTOR = 0.03 * 1e18; /** * @notice Calculates auction price. * @param referencePrice_ Recorded at kick, used to calculate start price. * @param kickTime_ Time when auction was kicked. * @return price_ Calculated auction price. */ function _auctionPrice( uint256 referencePrice_, uint256 kickTime_ ) view returns (uint256 price_) { uint256 elapsedMinutes = Maths.wdiv((block.timestamp - kickTime_) * 1e18, 1 minutes * 1e18); int256 timeAdjustment; if (elapsedMinutes < 120 * 1e18) { timeAdjustment = PRBMathSD59x18.mul(-1 * 1e18, int256(elapsedMinutes / 20)); price_ = 256 * Maths.wmul(referencePrice_, uint256(PRBMathSD59x18.exp2(timeAdjustment))); } else if (elapsedMinutes < 840 * 1e18) { timeAdjustment = PRBMathSD59x18.mul(-1 * 1e18, int256((elapsedMinutes - 120 * 1e18) / 120)); price_ = 4 * Maths.wmul(referencePrice_, uint256(PRBMathSD59x18.exp2(timeAdjustment))); } else { timeAdjustment = PRBMathSD59x18.mul(-1 * 1e18, int256((elapsedMinutes - 840 * 1e18) / 60)); price_ = Maths.wmul(referencePrice_, uint256(PRBMathSD59x18.exp2(timeAdjustment))) / 16; } } /** * @notice Calculates bond penalty factor. * @dev Called in kick and take. * @param debtToCollateral_ Borrower debt to collateral at time of kick. * @param neutralPrice_ `NP` of auction. * @param bondFactor_ Factor used to determine bondSize. * @param auctionPrice_ Auction price at the time of call or, for bucket takes, bucket price. * @return bpf_ Factor used in determining bond `reward` (positive) or `penalty` (negative). */ function _bpf( uint256 debtToCollateral_, uint256 neutralPrice_, uint256 bondFactor_, uint256 auctionPrice_ ) pure returns (int256) { int256 sign; if (debtToCollateral_ < neutralPrice_) { // BPF = BondFactor * min(1, max(-1, (neutralPrice - price) / (neutralPrice - debtToCollateral))) sign = Maths.minInt( 1e18, Maths.maxInt( -1 * 1e18, PRBMathSD59x18.div( int256(neutralPrice_) - int256(auctionPrice_), int256(neutralPrice_) - int256(debtToCollateral_) ) ) ); } else { int256 val = int256(neutralPrice_) - int256(auctionPrice_); if (val < 0 ) sign = -1e18; else if (val != 0) sign = 1e18; } return PRBMathSD59x18.mul(int256(bondFactor_), sign); } /** * @notice Calculates bond parameters of an auction. * @param borrowerDebt_ Borrower's debt before entering in liquidation. * @param npTpRatio_ Borrower's Np to Tp ratio */ function _bondParams( uint256 borrowerDebt_, uint256 npTpRatio_ ) pure returns (uint256 bondFactor_, uint256 bondSize_) { // bondFactor = max(min(MAX_BOND_FACTOR, (NP/TP_ratio - 1) / 10), MIN_BOND_FACTOR) bondFactor_ = Maths.max( Maths.min( MAX_BOND_FACTOR, (npTpRatio_ - 1e18) / 10 ), MIN_BOND_FACTOR ); bondSize_ = Maths.wmul(bondFactor_, borrowerDebt_); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import { Math } from '@openzeppelin/contracts/utils/math/Math.sol'; import { DepositsState } from '../../interfaces/pool/commons/IPoolState.sol'; import { _priceAt, MAX_FENWICK_INDEX } from '../helpers/PoolHelper.sol'; import { Maths } from './Maths.sol'; /** @title Deposits library @notice Internal library containing common logic for deposits management. @dev Implemented as `Fenwick Tree` data structure. */ library Deposits { /// @dev Max index supported in the `Fenwick` tree uint256 internal constant SIZE = 8192; /**************/ /*** Errors ***/ /**************/ // See `IPoolErrors` for descriptions error InvalidAmount(); /** * @notice Increase a value in the FenwickTree at an index. * @dev Starts at leaf/target and moved up towards root * @dev === Reverts on === * @dev unscaled amount to add is 0 `InvalidAmount()` * @param deposits_ Deposits state struct. * @param index_ The deposit index. * @param unscaledAddAmount_ The unscaled amount to increase deposit by. */ function unscaledAdd( DepositsState storage deposits_, uint256 index_, uint256 unscaledAddAmount_ ) internal { // revert if 0 amount is added. if (unscaledAddAmount_ == 0) revert InvalidAmount(); // price buckets are indexed starting at 0, Fenwick bit logic is more elegant starting at 1 ++index_; // unscaledAddAmount_ is the raw amount to add directly to the value at index_, unaffected by the scale array // For example, to denote an amount of deposit added to the array, we would need to call unscaledAdd with // (deposit amount) / scale(index). There are two reasons for this: // 1- scale(index) is often already known in the context of where unscaledAdd(..) is called, and we want to avoid // redundant iterations through the Fenwick tree. // 2- We often need to precisely change the value in the tree, avoiding the rounding that dividing by scale(index). // This is more relevant to unscaledRemove(...), where we need to ensure the value is precisely set to 0, but we // also prefer it here for consistency. uint256 value; uint256 scaling; uint256 newValue; while (index_ <= SIZE) { value = deposits_.values[index_]; scaling = deposits_.scaling[index_]; // Compute the new value to be put in location index_ newValue = value + unscaledAddAmount_; // Update unscaledAddAmount to propogate up the Fenwick tree // Note: we can't just multiply addAmount_ by scaling[i_] due to rounding // We need to track the precice change in values[i_] in order to ensure // obliterated indices remain zero after subsequent adding to related indices // if scaling==0, the actual scale value is 1, otherwise it is scaling if (scaling != 0) unscaledAddAmount_ = Maths.wmul(newValue, scaling) - Maths.wmul(value, scaling); deposits_.values[index_] = newValue; // traverse upwards through tree via "update" route index_ += lsb(index_); } } /** * @notice Finds index and sum of first bucket that EXCEEDS the given sum * @dev Used in `LUP` calculation * @param deposits_ Struct for deposits state. * @param targetSum_ The sum to find index for. * @return sumIndex_ Smallest index where prefixsum greater than the sum. * @return sumIndexSum_ Sum at index PRECEDING `sumIndex_`. * @return sumIndexScale_ Scale of bucket PRECEDING `sumIndex_`. */ function findIndexAndSumOfSum( DepositsState storage deposits_, uint256 targetSum_ ) internal view returns (uint256 sumIndex_, uint256 sumIndexSum_, uint256 sumIndexScale_) { // i iterates over bits from MSB to LSB. We check at each stage if the target sum is to the left or right of sumIndex_+i uint256 i = 4096; // 1 << (_numBits - 1) = 1 << (13 - 1) = 4096 uint256 runningScale = Maths.WAD; // We construct the target sumIndex_ bit by bit, from MSB to LSB. lowerIndexSum_ always maintains the sum // up to the current value of sumIndex_ uint256 lowerIndexSum; uint256 curIndex; uint256 value; uint256 scaling; uint256 scaledValue; while (i > 0) { // Consider if the target index is less than or greater than sumIndex_ + i curIndex = sumIndex_ + i; value = deposits_.values[curIndex]; scaling = deposits_.scaling[curIndex]; // Compute sum up to sumIndex_ + i scaledValue = lowerIndexSum + ( scaling != 0 ? Math.mulDiv( runningScale * scaling, value, 1e36 ) : Maths.wmul(runningScale, value) ); if (scaledValue < targetSum_) { // Target value is too small, need to consider increasing sumIndex_ still if (curIndex <= MAX_FENWICK_INDEX) { // sumIndex_+i is in range of Fenwick prices. Target index has this bit set to 1. sumIndex_ = curIndex; lowerIndexSum = scaledValue; } } else { // Target index has this bit set to 0 // scaling == 0 means scale factor == 1, otherwise scale factor == scaling if (scaling != 0) runningScale = Maths.floorWmul(runningScale, scaling); // Current scaledValue is <= targetSum_, it's a candidate value for sumIndexSum_ sumIndexSum_ = scaledValue; sumIndexScale_ = runningScale; } // Shift i to next less significant bit i = i >> 1; } } /** * @notice Finds index of passed sum. Helper function for `findIndexAndSumOfSum`. * @dev Used in `LUP` calculation * @param deposits_ Deposits state struct. * @param sum_ The sum to find index for. * @return sumIndex_ Smallest index where prefixsum greater than the sum. */ function findIndexOfSum( DepositsState storage deposits_, uint256 sum_ ) internal view returns (uint256 sumIndex_) { (sumIndex_,,) = findIndexAndSumOfSum(deposits_, sum_); } /** * @notice Get least significant bit (`LSB`) of integer `i_`. * @dev Used primarily to decrement the binary index in loops, iterating over range parents. * @param i_ The integer with which to return the `LSB`. */ function lsb( uint256 i_ ) internal pure returns (uint256 lsb_) { if (i_ != 0) { // "i & (-i)" lsb_ = i_ & ((i_ ^ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) + 1); } } /** * @notice Scale values in the tree from the index provided, upwards. * @dev Starts at passed in node and increments through range parent nodes, and ends at `8192`. * @param deposits_ Deposits state struct. * @param index_ The index to start scaling from. * @param factor_ The factor to scale the values by. */ function mult( DepositsState storage deposits_, uint256 index_, uint256 factor_ ) internal { // price buckets are indexed starting at 0, Fenwick bit logic is more elegant starting at 1 ++index_; uint256 sum; uint256 value; uint256 scaling; uint256 bit = lsb(index_); // Starting with the LSB of index, we iteratively move up towards the MSB of SIZE // Case 1: the bit of index_ is set to 1. In this case, the entire subtree below index_ // is scaled. So, we include factor_ into scaling[index_], and remember in sum how much // we increased the subtree by, so that we can use it in case we encounter 0 bits (below). // Case 2: The bit of index_ is set to 0. In this case, consider the subtree below the node // index_+bit. The subtree below that is not entirely scaled, but it does contain the // subtree what was scaled earlier. Therefore: we need to increment it's stored value // (in sum) which was set in a prior interation in case 1. while (bit <= SIZE) { if ((bit & index_) != 0) { // Case 1 as described above value = deposits_.values[index_]; scaling = deposits_.scaling[index_]; // Calc sum, will only be stored in range parents of starting node, index_ if (scaling != 0) { // Note: we can't just multiply by factor_ - 1 in the following line, as rounding will // cause obliterated indices to have nonzero values. Need to track the actual // precise delta in the value array uint256 scaledFactor = Maths.wmul(factor_, scaling); sum += Maths.wmul(scaledFactor, value) - Maths.wmul(scaling, value); // Apply scaling to all range parents less then starting node, index_ deposits_.scaling[index_] = scaledFactor; } else { // this node's scale factor is 1 sum += Maths.wmul(factor_, value) - value; deposits_.scaling[index_] = factor_; } // Unset the bit in index to continue traversing up the Fenwick tree index_ -= bit; } else { // Case 2 above. superRangeIndex is the index of the node to consider that // contains the sub range that was already scaled in prior iteration uint256 superRangeIndex = index_ + bit; value = (deposits_.values[superRangeIndex] += sum); scaling = deposits_.scaling[superRangeIndex]; // Need to be careful due to rounding to propagate actual changes upwards in tree. // sum is always equal to the actual value we changed deposits_.values[] by if (scaling != 0) sum = Maths.wmul(value, scaling) - Maths.wmul(value - sum, scaling); } // consider next most significant bit bit = bit << 1; } } /** * @notice Get prefix sum of all indexes from provided index downwards. * @dev Starts at tree root and decrements through range parent nodes summing from index `sumIndex_`'s range to index `0`. * @param deposits_ Deposits state struct. * @param sumIndex_ The index to receive the prefix sum. * @param sum_ The prefix sum from current index downwards. */ function prefixSum( DepositsState storage deposits_, uint256 sumIndex_ ) internal view returns (uint256 sum_) { // price buckets are indexed starting at 0, Fenwick bit logic is more elegant starting at 1 ++sumIndex_; uint256 runningScale = Maths.WAD; // Tracks scale(index_) as we move down Fenwick tree uint256 j = SIZE; // bit that iterates from MSB to LSB uint256 index = 0; // build up sumIndex bit by bit // Used to terminate loop. We don't need to consider final 0 bits of sumIndex_ uint256 indexLSB = lsb(sumIndex_); uint256 curIndex; while (j >= indexLSB) { curIndex = index + j; // Skip considering indices outside bounds of Fenwick tree if (curIndex > SIZE) continue; // We are considering whether to include node index + j in the sum or not. Either way, we need to scaling[index + j], // either to increment sum_ or to accumulate in runningScale uint256 scaled = deposits_.scaling[curIndex]; if (sumIndex_ & j != 0) { // node index + j of tree is included in sum uint256 value = deposits_.values[curIndex]; // Accumulate in sum_, recall that scaled==0 means that the scale factor is actually 1 sum_ += scaled != 0 ? Math.mulDiv( runningScale * scaled, value, 1e36 ) : Maths.wmul(runningScale, value); // Build up index bit by bit index = curIndex; // terminate if we've already matched sumIndex_ if (index == sumIndex_) break; } else { // node is not included in sum, but its scale needs to be included for subsequent sums if (scaled != 0) runningScale = Maths.floorWmul(runningScale, scaled); } // shift j to consider next less signficant bit j = j >> 1; } } /** * @notice Decrease a node in the `FenwickTree` at an index. * @dev Starts at leaf/target and moved up towards root. * @dev === Reverts on === * @dev unscaled amount to remove is 0 `InvalidAmount()` * @param deposits_ Deposits state struct. * @param index_ The deposit index. * @param unscaledRemoveAmount_ Unscaled amount to decrease deposit by. */ function unscaledRemove( DepositsState storage deposits_, uint256 index_, uint256 unscaledRemoveAmount_ ) internal { // revert if 0 amount is removed. if (unscaledRemoveAmount_ == 0) revert InvalidAmount(); // price buckets are indexed starting at 0, Fenwick bit logic is more elegant starting at 1 ++index_; // We operate with unscaledRemoveAmount_ here instead of a scaled quantity to avoid duplicate computation of scale factor // (thus redundant iterations through the Fenwick tree), and ALSO so that we can set the value of a given deposit exactly // to 0. while (index_ <= SIZE) { // Decrement deposits_ at index_ for removeAmount, storing new value in value uint256 value = (deposits_.values[index_] -= unscaledRemoveAmount_); uint256 scaling = deposits_.scaling[index_]; // If scale factor != 1, we need to adjust unscaledRemoveAmount by scale factor to adjust values further up in tree // On the line below, it would be tempting to replace this with: // unscaledRemoveAmount_ = Maths.wmul(unscaledRemoveAmount, scaling). This will introduce nonzero values up // the tree due to rounding. It's important to compute the actual change in deposits_.values[index_] // and propogate that upwards. if (scaling != 0) unscaledRemoveAmount_ = Maths.wmul(value + unscaledRemoveAmount_, scaling) - Maths.wmul(value, scaling); // Traverse upward through the "update" path of the Fenwick tree index_ += lsb(index_); } } /** * @notice Scale tree starting from given index. * @dev Starts at leaf/target and moved up towards root. * @param deposits_ Deposits state struct. * @param index_ The deposit index. * @return scaled_ Scaled value. */ function scale( DepositsState storage deposits_, uint256 index_ ) internal view returns (uint256 scaled_) { // price buckets are indexed starting at 0, Fenwick bit logic is more elegant starting at 1 ++index_; // start with scaled_1 = 1 scaled_ = Maths.WAD; while (index_ <= SIZE) { // Traverse up through Fenwick tree via "update" path, accumulating scale factors as we go uint256 scaling = deposits_.scaling[index_]; // scaling==0 means actual scale factor is 1 if (scaling != 0) scaled_ = Maths.wmul(scaled_, scaling); index_ += lsb(index_); } } /** * @notice Returns sum of all deposits. * @param deposits_ Deposits state struct. * @return Sum of all deposits in tree. */ function treeSum( DepositsState storage deposits_ ) internal view returns (uint256) { // In a scaled Fenwick tree, sum is at the root node and never scaled return deposits_.values[SIZE]; } /** * @notice Returns deposit value for a given deposit index. * @param deposits_ Deposits state struct. * @param index_ The deposit index. * @return depositValue_ Value of the deposit. */ function valueAt( DepositsState storage deposits_, uint256 index_ ) internal view returns (uint256 depositValue_) { // Get unscaled value at index and multiply by scale depositValue_ = Maths.wmul(unscaledValueAt(deposits_, index_), scale(deposits_,index_)); } /** * @notice Returns unscaled (deposit without interest) deposit value for a given deposit index. * @param deposits_ Deposits state struct. * @param index_ The deposit index. * @return unscaledDepositValue_ Value of unscaled deposit. */ function unscaledValueAt( DepositsState storage deposits_, uint256 index_ ) internal view returns (uint256 unscaledDepositValue_) { // In a scaled Fenwick tree, sum is at the root node, but needs to be scaled ++index_; uint256 j = 1; // Returns the unscaled value at the node. We consider the unscaled value for two reasons: // 1- If we want to zero out deposit in bucket, we need to subtract the exact unscaled value // 2- We may already have computed the scale factor, so we can avoid duplicate traversal unscaledDepositValue_ = deposits_.values[index_]; uint256 curIndex; uint256 value; uint256 scaling; while (j & index_ == 0) { curIndex = index_ - j; value = deposits_.values[curIndex]; scaling = deposits_.scaling[curIndex]; unscaledDepositValue_ -= scaling != 0 ? Maths.wmul(scaling, value) : value; j = j << 1; } } /** * @notice Returns `LUP` for a given debt value (capped at min bucket price). * @param deposits_ Deposits state struct. * @param debt_ The debt amount to calculate `LUP` for. * @return `LUP` for given debt. */ function getLup( DepositsState storage deposits_, uint256 debt_ ) internal view returns (uint256) { return _priceAt(findIndexOfSum(deposits_, debt_)); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import { Math } from '@openzeppelin/contracts/utils/math/Math.sol'; import { Bucket, Lender } from '../../interfaces/pool/commons/IPoolState.sol'; import { Maths } from './Maths.sol'; /** @title Buckets library @notice Internal library containing common logic for buckets management. */ library Buckets { /**************/ /*** Events ***/ /**************/ // See `IPoolError` for descriptions error BucketBankruptcyBlock(); /***********************************/ /*** Bucket Management Functions ***/ /***********************************/ /** * @notice Add collateral to a bucket and updates `LP` for bucket and lender with the amount coresponding to collateral amount added. * @dev Increment `bucket.collateral` and `bucket.lps` accumulator * @dev - `addLenderLP`: * @dev increment `lender.lps` accumulator and `lender.depositTime` state * @param lender_ Address of the lender. * @param deposit_ Current bucket deposit (quote tokens). Used to calculate bucket's exchange rate / `LP`. * @param collateralAmountToAdd_ Additional collateral amount to add to bucket. * @param bucketPrice_ Bucket price. * @return addedLP_ Amount of bucket `LP` for the collateral amount added. */ function addCollateral( Bucket storage bucket_, address lender_, uint256 deposit_, uint256 collateralAmountToAdd_, uint256 bucketPrice_ ) internal returns (uint256 addedLP_) { // cannot deposit in the same block when bucket becomes insolvent uint256 bankruptcyTime = bucket_.bankruptcyTime; if (bankruptcyTime == block.timestamp) revert BucketBankruptcyBlock(); // calculate amount of LP to be added for the amount of collateral added to bucket addedLP_ = collateralToLP( bucket_.collateral, bucket_.lps, deposit_, collateralAmountToAdd_, bucketPrice_, Math.Rounding.Down ); // update bucket LP balance and collateral // update bucket collateral bucket_.collateral += collateralAmountToAdd_; // update bucket and lender LP balance and deposit timestamp bucket_.lps += addedLP_; addLenderLP(bucket_, bankruptcyTime, lender_, addedLP_); } /** * @notice Add amount of `LP` for a given lender in a given bucket. * @dev Increments lender lps accumulator and updates the deposit time. * @param bucket_ Bucket to record lender `LP`. * @param bankruptcyTime_ Time when bucket become insolvent. * @param lender_ Lender address to add `LP` for in the given bucket. * @param lpAmount_ Amount of `LP` to be recorded for the given lender. */ function addLenderLP( Bucket storage bucket_, uint256 bankruptcyTime_, address lender_, uint256 lpAmount_ ) internal { if (lpAmount_ != 0) { Lender storage lender = bucket_.lenders[lender_]; if (bankruptcyTime_ >= lender.depositTime) lender.lps = lpAmount_; else lender.lps += lpAmount_; lender.depositTime = block.timestamp; } } /**********************/ /*** View Functions ***/ /**********************/ /****************************/ /*** Assets to LP helpers ***/ /****************************/ /** * @notice Returns the amount of bucket `LP` calculated for the given amount of collateral. * @param bucketCollateral_ Amount of collateral in bucket. * @param bucketLP_ Amount of `LP` in bucket. * @param deposit_ Current bucket deposit (quote tokens). Used to calculate bucket's exchange rate / `LP`. * @param collateral_ The amount of collateral to calculate bucket LP for. * @param bucketPrice_ Bucket's price. * @param rounding_ The direction of rounding when calculating LP (down when adding, up when removing collateral from pool). * @return Amount of `LP` calculated for the amount of collateral. */ function collateralToLP( uint256 bucketCollateral_, uint256 bucketLP_, uint256 deposit_, uint256 collateral_, uint256 bucketPrice_, Math.Rounding rounding_ ) internal pure returns (uint256) { // case when there's no deposit nor collateral in bucket if (deposit_ == 0 && bucketCollateral_ == 0) return Maths.wmul(collateral_, bucketPrice_); // case when there's deposit or collateral in bucket but no LP to cover if (bucketLP_ == 0) return Maths.wmul(collateral_, bucketPrice_); // case when there's deposit or collateral and bucket has LP balance return Math.mulDiv( bucketLP_, collateral_ * bucketPrice_, deposit_ * Maths.WAD + bucketCollateral_ * bucketPrice_, rounding_ ); } /** * @notice Returns the amount of `LP` calculated for the given amount of quote tokens. * @param bucketCollateral_ Amount of collateral in bucket. * @param bucketLP_ Amount of `LP` in bucket. * @param deposit_ Current bucket deposit (quote tokens). Used to calculate bucket's exchange rate / `LP`. * @param quoteTokens_ The amount of quote tokens to calculate `LP` amount for. * @param bucketPrice_ Bucket's price. * @param rounding_ The direction of rounding when calculating LP (down when adding, up when removing quote tokens from pool). * @return The amount of `LP` coresponding to the given quote tokens in current bucket. */ function quoteTokensToLP( uint256 bucketCollateral_, uint256 bucketLP_, uint256 deposit_, uint256 quoteTokens_, uint256 bucketPrice_, Math.Rounding rounding_ ) internal pure returns (uint256) { // case when there's no deposit nor collateral in bucket if (deposit_ == 0 && bucketCollateral_ == 0) return quoteTokens_; // case when there's deposit or collateral in bucket but no LP to cover if (bucketLP_ == 0) return quoteTokens_; // case when there's deposit or collateral and bucket has LP balance return Math.mulDiv( bucketLP_, quoteTokens_ * Maths.WAD, deposit_ * Maths.WAD + bucketCollateral_ * bucketPrice_, rounding_ ); } /****************************/ /*** LP to Assets helpers ***/ /****************************/ /** * @notice Returns the amount of collateral calculated for the given amount of lp * @dev The value returned is not capped at collateral amount available in bucket. * @param bucketCollateral_ Amount of collateral in bucket. * @param bucketLP_ Amount of `LP` in bucket. * @param deposit_ Current bucket deposit (quote tokens). Used to calculate bucket's exchange rate / `LP`. * @param lp_ The amount of LP to calculate collateral amount for. * @param bucketPrice_ Bucket's price. * @return The amount of collateral coresponding to the given `LP` in current bucket. */ function lpToCollateral( uint256 bucketCollateral_, uint256 bucketLP_, uint256 deposit_, uint256 lp_, uint256 bucketPrice_, Math.Rounding rounding_ ) internal pure returns (uint256) { // case when there's no deposit nor collateral in bucket if (deposit_ == 0 && bucketCollateral_ == 0) return Maths.wdiv(lp_, bucketPrice_); // case when there's deposit or collateral in bucket but no LP to cover if (bucketLP_ == 0) return Maths.wdiv(lp_, bucketPrice_); // case when there's deposit or collateral and bucket has LP balance return Math.mulDiv( deposit_ * Maths.WAD + bucketCollateral_ * bucketPrice_, lp_, bucketLP_ * bucketPrice_, rounding_ ); } /** * @notice Returns the amount of quote token (in value) calculated for the given amount of `LP`. * @dev The value returned is not capped at available bucket deposit. * @param bucketCollateral_ Amount of collateral in bucket. * @param bucketLP_ Amount of `LP` in bucket. * @param deposit_ Current bucket deposit (quote tokens). Used to calculate bucket's exchange rate / `LP`. * @param lp_ The amount of LP to calculate quote tokens amount for. * @param bucketPrice_ Bucket's price. * @return The amount coresponding to the given quote tokens in current bucket. */ function lpToQuoteTokens( uint256 bucketCollateral_, uint256 bucketLP_, uint256 deposit_, uint256 lp_, uint256 bucketPrice_, Math.Rounding rounding_ ) internal pure returns (uint256) { // case when there's no deposit nor collateral in bucket if (deposit_ == 0 && bucketCollateral_ == 0) return lp_; // case when there's deposit or collateral in bucket but no LP to cover if (bucketLP_ == 0) return lp_; // case when there's deposit or collateral and bucket has LP balance return Math.mulDiv( deposit_ * Maths.WAD + bucketCollateral_ * bucketPrice_, lp_, bucketLP_ * Maths.WAD, rounding_ ); } /****************************/ /*** Exchange Rate helper ***/ /****************************/ /** * @notice Returns the exchange rate for a given bucket (conversion of 1 lp to quote token). * @param bucketCollateral_ Amount of collateral in bucket. * @param bucketLP_ Amount of `LP` in bucket. * @param bucketDeposit_ The amount of quote tokens deposited in the given bucket. * @param bucketPrice_ Bucket's price. */ function getExchangeRate( uint256 bucketCollateral_, uint256 bucketLP_, uint256 bucketDeposit_, uint256 bucketPrice_ ) internal pure returns (uint256) { return lpToQuoteTokens( bucketCollateral_, bucketLP_, bucketDeposit_, Maths.WAD, bucketPrice_, Math.Rounding.Up ); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import { PRBMathSD59x18 } from "@prb-math/contracts/PRBMathSD59x18.sol"; import { AuctionsState, Borrower, DepositsState, Loan, LoansState } from '../../interfaces/pool/commons/IPoolState.sol'; import { _priceAt } from '../helpers/PoolHelper.sol'; import { Deposits } from './Deposits.sol'; import { Maths } from './Maths.sol'; /** @title Loans library @notice Internal library containing common logic for loans management. @dev The `Loans` heap is a `Max Heap` data structure (complete binary tree), the root node is the loan with the highest t0 threshold price (`TP`) at a given time. The heap is represented as an array, where the first element is a dummy element (`Loan(address(0), 0)`) and the first value of the heap starts at index `1`, `ROOT_INDEX`. The t0 threshold price of a loan's parent is always greater than or equal to the t0 threshold price of the loan. @dev This code was modified from the following source: https://github.com/zmitton/eth-heap/blob/master/contracts/Heap.sol */ library Loans { uint256 constant ROOT_INDEX = 1; /**************/ /*** Errors ***/ /**************/ // See `IPoolErrors` for descriptions error ZeroDebtToCollateral(); /***********************/ /*** Initialization ***/ /***********************/ /** * @notice Initializes Loans Max Heap. * @dev Organizes loans so `Highest t0 threshold price` can be retrieved easily. * @param loans_ Holds Loan heap data. */ function init(LoansState storage loans_) internal { loans_.loans.push(Loan(address(0), 0)); } /***********************************/ /*** Loans Management Functions ***/ /***********************************/ /** * @notice Updates a loan: updates heap (`upsert` if `TP` not `0`, `remove` otherwise) and borrower balance. * @dev === Write state === * @dev - `_upsert`: * @dev insert or update loan in `loans` array * @dev - `remove`: * @dev remove loan from `loans` array * @dev - update borrower in `address => borrower` mapping * @param loans_ Holds loans heap data. * @param borrower_ Borrower struct with borrower details. * @param borrowerAddress_ Borrower's address to update. * @param poolRate_ Pool's current rate. * @param inAuction_ Whether the loan is in auction or not. * @param npTpRatioUpdate_ Whether the Np to Tp ratio of borrower should be updated or not. */ function update( LoansState storage loans_, Borrower memory borrower_, address borrowerAddress_, uint256 poolRate_, bool inAuction_, bool npTpRatioUpdate_ ) internal { bool activeBorrower = borrower_.t0Debt != 0 && borrower_.collateral != 0; uint256 t0DebtToCollateral = activeBorrower ? Maths.wdiv(borrower_.t0Debt, borrower_.collateral) : 0; // loan not in auction, update t0 threshold price and position in heap if (!inAuction_ ) { // get the loan id inside the heap uint256 loanId = loans_.indices[borrowerAddress_]; if (activeBorrower) { // revert if t0 threshold price is zero if (t0DebtToCollateral == 0) revert ZeroDebtToCollateral(); // update heap, insert if a new loan, update loan if already in heap _upsert(loans_, borrowerAddress_, loanId, SafeCast.toUint96(t0DebtToCollateral)); // if loan is in heap and borrwer is no longer active (no debt, no collateral) then remove loan from heap } else if (loanId != 0) { remove(loans_, borrowerAddress_, loanId); } } // update Np to Tp ratio of borrower if (npTpRatioUpdate_) { borrower_.npTpRatio = 1e18 + uint256(PRBMathSD59x18.sqrt(int256(poolRate_))) / 2; } // save borrower state loans_.borrowers[borrowerAddress_] = borrower_; } /**************************************/ /*** Loans Heap Internal Functions ***/ /**************************************/ /** * @notice Moves a `Loan` up the heap. * @param loans_ Holds loans heap data. * @param loan_ `Loan` to be moved. * @param index_ Index of `Loan` to be moved to. */ function _bubbleUp(LoansState storage loans_, Loan memory loan_, uint index_) private { uint256 count = loans_.loans.length; if (index_ == ROOT_INDEX || loan_.t0DebtToCollateral <= loans_.loans[index_ / 2].t0DebtToCollateral){ _insert(loans_, loan_, index_, count); } else { _insert(loans_, loans_.loans[index_ / 2], index_, count); _bubbleUp(loans_, loan_, index_ / 2); } } /** * @notice Moves a `Loan` down the heap. * @param loans_ Holds loans heap data. * @param loan_ `Loan` to be moved. * @param index_ Index of `Loan` to be moved to. */ function _bubbleDown(LoansState storage loans_, Loan memory loan_, uint index_) private { // Left child index. uint cIndex = index_ * 2; uint256 count = loans_.loans.length; if (count <= cIndex) { _insert(loans_, loan_, index_, count); } else { Loan memory largestChild = loans_.loans[cIndex]; if (count > cIndex + 1 && loans_.loans[cIndex + 1].t0DebtToCollateral > largestChild.t0DebtToCollateral) { largestChild = loans_.loans[++cIndex]; } if (largestChild.t0DebtToCollateral <= loan_.t0DebtToCollateral) { _insert(loans_, loan_, index_, count); } else { _insert(loans_, largestChild, index_, count); _bubbleDown(loans_, loan_, cIndex); } } } /** * @notice Inserts a `Loan` in the heap. * @param loans_ Holds loans heap data. * @param loan_ `Loan` to be inserted. * @param index_ Index of `Loan` to be inserted at. */ function _insert(LoansState storage loans_, Loan memory loan_, uint index_, uint256 count_) private { if (index_ == count_) loans_.loans.push(loan_); else loans_.loans[index_] = loan_; loans_.indices[loan_.borrower] = index_; } /** * @notice Removes `Loan` from heap given borrower address. * @param loans_ Holds loans heap data. * @param borrower_ Borrower address whose `Loan` is being updated or inserted. * @param index_ Index of `Loan` to be removed. */ function remove(LoansState storage loans_, address borrower_, uint256 index_) internal { delete loans_.indices[borrower_]; uint256 tailIndex = loans_.loans.length - 1; if (index_ == tailIndex) loans_.loans.pop(); // we're removing the tail, pop without sorting else { Loan memory tail = loans_.loans[tailIndex]; loans_.loans.pop(); // remove tail loan _bubbleUp(loans_, tail, index_); _bubbleDown(loans_, loans_.loans[index_], index_); } } /** * @notice Performs an insert or an update dependent on borrowers existance. * @param loans_ Holds loans heap data. * @param borrower_ Borrower address that is being updated or inserted. * @param index_ Index of `Loan` to be upserted. * @param t0DebtToCollateral_ Borrower t0 debt to collateral that is updated or inserted. */ function _upsert( LoansState storage loans_, address borrower_, uint256 index_, uint96 t0DebtToCollateral_ ) internal { // Loan exists, update in place. if (index_ != 0) { Loan memory currentLoan = loans_.loans[index_]; if (currentLoan.t0DebtToCollateral > t0DebtToCollateral_) { currentLoan.t0DebtToCollateral = t0DebtToCollateral_; _bubbleDown(loans_, currentLoan, index_); } else { currentLoan.t0DebtToCollateral = t0DebtToCollateral_; _bubbleUp(loans_, currentLoan, index_); } // New loan, insert it } else { _bubbleUp(loans_, Loan(borrower_, t0DebtToCollateral_), loans_.loans.length); } } /**********************/ /*** View Functions ***/ /**********************/ /** * @notice Retreives `Loan` by index, `index_`. * @param loans_ Holds loans heap data. * @param index_ Index to retrieve `Loan`. * @return `Loan` struct retrieved by index. */ function getByIndex(LoansState storage loans_, uint256 index_) internal view returns(Loan memory) { return loans_.loans.length > index_ ? loans_.loans[index_] : Loan(address(0), 0); } /** * @notice Retreives `Loan` with the highest t0 threshold price value. * @param loans_ Holds loans heap data. * @return `Max Loan` in the heap. */ function getMax(LoansState storage loans_) internal view returns(Loan memory) { return getByIndex(loans_, ROOT_INDEX); } /** * @notice Returns number of loans in pool. * @param loans_ Holds loans heap data. * @return Number of loans in pool. */ function noOfLoans(LoansState storage loans_) internal view returns (uint256) { return loans_.loans.length - 1; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.18; /** @title Maths library @notice Internal library containing common maths. */ library Maths { uint256 internal constant WAD = 1e18; uint256 internal constant RAY = 1e27; function wmul(uint256 x, uint256 y) internal pure returns (uint256) { return (x * y + WAD / 2) / WAD; } function floorWmul(uint256 x, uint256 y) internal pure returns (uint256) { return (x * y) / WAD; } function ceilWmul(uint256 x, uint256 y) internal pure returns (uint256) { return (x * y + WAD - 1) / WAD; } function wdiv(uint256 x, uint256 y) internal pure returns (uint256) { return (x * WAD + y / 2) / y; } function floorWdiv(uint256 x, uint256 y) internal pure returns (uint256) { return (x * WAD) / y; } function ceilWdiv(uint256 x, uint256 y) internal pure returns (uint256) { return (x * WAD + y - 1) / y; } function ceilDiv(uint256 x, uint256 y) internal pure returns (uint256) { return (x + y - 1) / y; } function max(uint256 x, uint256 y) internal pure returns (uint256) { return x >= y ? x : y; } function min(uint256 x, uint256 y) internal pure returns (uint256) { return x <= y ? x : y; } function wad(uint256 x) internal pure returns (uint256) { return x * WAD; } function rmul(uint256 x, uint256 y) internal pure returns (uint256) { return (x * y + RAY / 2) / RAY; } function rpow(uint256 x, uint256 n) internal pure returns (uint256 z) { z = n % 2 != 0 ? x : RAY; for (n /= 2; n != 0; n /= 2) { x = rmul(x, x); if (n % 2 != 0) { z = rmul(z, x); } } } /*************************/ /*** Integer Functions ***/ /*************************/ function maxInt(int256 x, int256 y) internal pure returns (int256) { return x >= y ? x : y; } function minInt(int256 x, int256 y) internal pure returns (int256) { return x <= y ? x : y; } }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivFixedPointOverflow(uint256 prod1); /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator); /// @notice Emitted when one of the inputs is type(int256).min. error PRBMath__MulDivSignedInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows int256. error PRBMath__MulDivSignedOverflow(uint256 rAbs); /// @notice Emitted when the input is MIN_SD59x18. error PRBMathSD59x18__AbsInputTooSmall(); /// @notice Emitted when ceiling a number overflows SD59x18. error PRBMathSD59x18__CeilOverflow(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__DivInputTooSmall(); /// @notice Emitted when one of the intermediary unsigned results overflows SD59x18. error PRBMathSD59x18__DivOverflow(uint256 rAbs); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathSD59x18__ExpInputTooBig(int256 x); /// @notice Emitted when the input is greater than 192. error PRBMathSD59x18__Exp2InputTooBig(int256 x); /// @notice Emitted when flooring a number underflows SD59x18. error PRBMathSD59x18__FloorUnderflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18. error PRBMathSD59x18__FromIntOverflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18. error PRBMathSD59x18__FromIntUnderflow(int256 x); /// @notice Emitted when the product of the inputs is negative. error PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y); /// @notice Emitted when multiplying the inputs overflows SD59x18. error PRBMathSD59x18__GmOverflow(int256 x, int256 y); /// @notice Emitted when the input is less than or equal to zero. error PRBMathSD59x18__LogInputTooSmall(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__MulInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__MulOverflow(uint256 rAbs); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__PowuOverflow(uint256 rAbs); /// @notice Emitted when the input is negative. error PRBMathSD59x18__SqrtNegativeInput(int256 x); /// @notice Emitted when the calculating the square root overflows SD59x18. error PRBMathSD59x18__SqrtOverflow(int256 x); /// @notice Emitted when addition overflows UD60x18. error PRBMathUD60x18__AddOverflow(uint256 x, uint256 y); /// @notice Emitted when ceiling a number overflows UD60x18. error PRBMathUD60x18__CeilOverflow(uint256 x); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathUD60x18__ExpInputTooBig(uint256 x); /// @notice Emitted when the input is greater than 192. error PRBMathUD60x18__Exp2InputTooBig(uint256 x); /// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18. error PRBMathUD60x18__FromUintOverflow(uint256 x); /// @notice Emitted when multiplying the inputs overflows UD60x18. error PRBMathUD60x18__GmOverflow(uint256 x, uint256 y); /// @notice Emitted when the input is less than 1. error PRBMathUD60x18__LogInputTooSmall(uint256 x); /// @notice Emitted when the calculating the square root overflows UD60x18. error PRBMathUD60x18__SqrtOverflow(uint256 x); /// @notice Emitted when subtraction underflows UD60x18. error PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y); /// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library /// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point /// representation. When it does not, it is explicitly mentioned in the NatSpec documentation. library PRBMath { /// STRUCTS /// struct SD59x18 { int256 value; } struct UD60x18 { uint256 value; } /// STORAGE /// /// @dev How many trailing decimals can be represented. uint256 internal constant SCALE = 1e18; /// @dev Largest power of two divisor of SCALE. uint256 internal constant SCALE_LPOTD = 262144; /// @dev SCALE inverted mod 2^256. uint256 internal constant SCALE_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281; /// FUNCTIONS /// /// @notice Calculates the binary exponent of x using the binary fraction method. /// @dev Has to use 192.64-bit fixed-point numbers. /// See https://ethereum.stackexchange.com/a/96594/24693. /// @param x The exponent as an unsigned 192.64-bit fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function exp2(uint256 x) internal pure returns (uint256 result) { unchecked { // Start from 0.5 in the 192.64-bit fixed-point format. result = 0x800000000000000000000000000000000000000000000000; // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows // because the initial result is 2^191 and all magic factors are less than 2^65. if (x & 0x8000000000000000 > 0) { result = (result * 0x16A09E667F3BCC909) >> 64; } if (x & 0x4000000000000000 > 0) { result = (result * 0x1306FE0A31B7152DF) >> 64; } if (x & 0x2000000000000000 > 0) { result = (result * 0x1172B83C7D517ADCE) >> 64; } if (x & 0x1000000000000000 > 0) { result = (result * 0x10B5586CF9890F62A) >> 64; } if (x & 0x800000000000000 > 0) { result = (result * 0x1059B0D31585743AE) >> 64; } if (x & 0x400000000000000 > 0) { result = (result * 0x102C9A3E778060EE7) >> 64; } if (x & 0x200000000000000 > 0) { result = (result * 0x10163DA9FB33356D8) >> 64; } if (x & 0x100000000000000 > 0) { result = (result * 0x100B1AFA5ABCBED61) >> 64; } if (x & 0x80000000000000 > 0) { result = (result * 0x10058C86DA1C09EA2) >> 64; } if (x & 0x40000000000000 > 0) { result = (result * 0x1002C605E2E8CEC50) >> 64; } if (x & 0x20000000000000 > 0) { result = (result * 0x100162F3904051FA1) >> 64; } if (x & 0x10000000000000 > 0) { result = (result * 0x1000B175EFFDC76BA) >> 64; } if (x & 0x8000000000000 > 0) { result = (result * 0x100058BA01FB9F96D) >> 64; } if (x & 0x4000000000000 > 0) { result = (result * 0x10002C5CC37DA9492) >> 64; } if (x & 0x2000000000000 > 0) { result = (result * 0x1000162E525EE0547) >> 64; } if (x & 0x1000000000000 > 0) { result = (result * 0x10000B17255775C04) >> 64; } if (x & 0x800000000000 > 0) { result = (result * 0x1000058B91B5BC9AE) >> 64; } if (x & 0x400000000000 > 0) { result = (result * 0x100002C5C89D5EC6D) >> 64; } if (x & 0x200000000000 > 0) { result = (result * 0x10000162E43F4F831) >> 64; } if (x & 0x100000000000 > 0) { result = (result * 0x100000B1721BCFC9A) >> 64; } if (x & 0x80000000000 > 0) { result = (result * 0x10000058B90CF1E6E) >> 64; } if (x & 0x40000000000 > 0) { result = (result * 0x1000002C5C863B73F) >> 64; } if (x & 0x20000000000 > 0) { result = (result * 0x100000162E430E5A2) >> 64; } if (x & 0x10000000000 > 0) { result = (result * 0x1000000B172183551) >> 64; } if (x & 0x8000000000 > 0) { result = (result * 0x100000058B90C0B49) >> 64; } if (x & 0x4000000000 > 0) { result = (result * 0x10000002C5C8601CC) >> 64; } if (x & 0x2000000000 > 0) { result = (result * 0x1000000162E42FFF0) >> 64; } if (x & 0x1000000000 > 0) { result = (result * 0x10000000B17217FBB) >> 64; } if (x & 0x800000000 > 0) { result = (result * 0x1000000058B90BFCE) >> 64; } if (x & 0x400000000 > 0) { result = (result * 0x100000002C5C85FE3) >> 64; } if (x & 0x200000000 > 0) { result = (result * 0x10000000162E42FF1) >> 64; } if (x & 0x100000000 > 0) { result = (result * 0x100000000B17217F8) >> 64; } if (x & 0x80000000 > 0) { result = (result * 0x10000000058B90BFC) >> 64; } if (x & 0x40000000 > 0) { result = (result * 0x1000000002C5C85FE) >> 64; } if (x & 0x20000000 > 0) { result = (result * 0x100000000162E42FF) >> 64; } if (x & 0x10000000 > 0) { result = (result * 0x1000000000B17217F) >> 64; } if (x & 0x8000000 > 0) { result = (result * 0x100000000058B90C0) >> 64; } if (x & 0x4000000 > 0) { result = (result * 0x10000000002C5C860) >> 64; } if (x & 0x2000000 > 0) { result = (result * 0x1000000000162E430) >> 64; } if (x & 0x1000000 > 0) { result = (result * 0x10000000000B17218) >> 64; } if (x & 0x800000 > 0) { result = (result * 0x1000000000058B90C) >> 64; } if (x & 0x400000 > 0) { result = (result * 0x100000000002C5C86) >> 64; } if (x & 0x200000 > 0) { result = (result * 0x10000000000162E43) >> 64; } if (x & 0x100000 > 0) { result = (result * 0x100000000000B1721) >> 64; } if (x & 0x80000 > 0) { result = (result * 0x10000000000058B91) >> 64; } if (x & 0x40000 > 0) { result = (result * 0x1000000000002C5C8) >> 64; } if (x & 0x20000 > 0) { result = (result * 0x100000000000162E4) >> 64; } if (x & 0x10000 > 0) { result = (result * 0x1000000000000B172) >> 64; } if (x & 0x8000 > 0) { result = (result * 0x100000000000058B9) >> 64; } if (x & 0x4000 > 0) { result = (result * 0x10000000000002C5D) >> 64; } if (x & 0x2000 > 0) { result = (result * 0x1000000000000162E) >> 64; } if (x & 0x1000 > 0) { result = (result * 0x10000000000000B17) >> 64; } if (x & 0x800 > 0) { result = (result * 0x1000000000000058C) >> 64; } if (x & 0x400 > 0) { result = (result * 0x100000000000002C6) >> 64; } if (x & 0x200 > 0) { result = (result * 0x10000000000000163) >> 64; } if (x & 0x100 > 0) { result = (result * 0x100000000000000B1) >> 64; } if (x & 0x80 > 0) { result = (result * 0x10000000000000059) >> 64; } if (x & 0x40 > 0) { result = (result * 0x1000000000000002C) >> 64; } if (x & 0x20 > 0) { result = (result * 0x10000000000000016) >> 64; } if (x & 0x10 > 0) { result = (result * 0x1000000000000000B) >> 64; } if (x & 0x8 > 0) { result = (result * 0x10000000000000006) >> 64; } if (x & 0x4 > 0) { result = (result * 0x10000000000000003) >> 64; } if (x & 0x2 > 0) { result = (result * 0x10000000000000001) >> 64; } if (x & 0x1 > 0) { result = (result * 0x10000000000000001) >> 64; } // We're doing two things at the same time: // // 1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191 // rather than 192. // 2. Convert the result to the unsigned 60.18-decimal fixed-point format. // // This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n". result *= SCALE; result >>= (191 - (x >> 64)); } } /// @notice Finds the zero-based index of the first one in the binary representation of x. /// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set /// @param x The uint256 number for which to find the index of the most significant bit. /// @return msb The index of the most significant bit as an uint256. function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) { if (x >= 2**128) { x >>= 128; msb += 128; } if (x >= 2**64) { x >>= 64; msb += 64; } if (x >= 2**32) { x >>= 32; msb += 32; } if (x >= 2**16) { x >>= 16; msb += 16; } if (x >= 2**8) { x >>= 8; msb += 8; } if (x >= 2**4) { x >>= 4; msb += 4; } if (x >= 2**2) { x >>= 2; msb += 2; } if (x >= 2**1) { // No need to shift x any more. msb += 1; } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. /// /// Requirements: /// - The denominator cannot be zero. /// - The result must fit within uint256. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The multiplicand as an uint256. /// @param y The multiplier as an uint256. /// @param denominator The divisor as an uint256. /// @return result The result as an uint256. function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { unchecked { result = prod0 / denominator; } return result; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (prod1 >= denominator) { revert PRBMath__MulDivOverflow(prod1, denominator); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. unchecked { // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 lpotdod = denominator & (~denominator + 1); assembly { // Divide denominator by lpotdod. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one. lpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * lpotdod; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /// @notice Calculates floor(x*y÷1e18) with full precision. /// /// @dev Variant of "mulDiv" with constant folding, i.e. in which the denominator is always 1e18. Before returning the /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of /// being rounded to 1e-18. See "Listing 6" and text above it at https://accu.org/index.php/journals/1717. /// /// Requirements: /// - The result must fit within uint256. /// /// Caveats: /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works. /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations: /// 1. x * y = type(uint256).max * SCALE /// 2. (x * y) % SCALE >= SCALE / 2 /// /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) { uint256 prod0; uint256 prod1; assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } if (prod1 >= SCALE) { revert PRBMath__MulDivFixedPointOverflow(prod1); } uint256 remainder; uint256 roundUpUnit; assembly { remainder := mulmod(x, y, SCALE) roundUpUnit := gt(remainder, 499999999999999999) } if (prod1 == 0) { unchecked { result = (prod0 / SCALE) + roundUpUnit; return result; } } assembly { result := add( mul( or( div(sub(prod0, remainder), SCALE_LPOTD), mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1)) ), SCALE_INVERSE ), roundUpUnit ) } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev An extension of "mulDiv" for signed numbers. Works by computing the signs and the absolute values separately. /// /// Requirements: /// - None of the inputs can be type(int256).min. /// - The result must fit within int256. /// /// @param x The multiplicand as an int256. /// @param y The multiplier as an int256. /// @param denominator The divisor as an int256. /// @return result The result as an int256. function mulDivSigned( int256 x, int256 y, int256 denominator ) internal pure returns (int256 result) { if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) { revert PRBMath__MulDivSignedInputTooSmall(); } // Get hold of the absolute values of x, y and the denominator. uint256 ax; uint256 ay; uint256 ad; unchecked { ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); ad = denominator < 0 ? uint256(-denominator) : uint256(denominator); } // Compute the absolute value of (x*y)÷denominator. The result must fit within int256. uint256 rAbs = mulDiv(ax, ay, ad); if (rAbs > uint256(type(int256).max)) { revert PRBMath__MulDivSignedOverflow(rAbs); } // Get the signs of x, y and the denominator. uint256 sx; uint256 sy; uint256 sd; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) sd := sgt(denominator, sub(0, 1)) } // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs. // If yes, the result should be negative. result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs); } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The uint256 number for which to calculate the square root. /// @return result The result as an uint256. function sqrt(uint256 x) internal pure returns (uint256 result) { if (x == 0) { return 0; } // Set the initial guess to the least power of two that is greater than or equal to sqrt(x). uint256 xAux = uint256(x); result = 1; if (xAux >= 0x100000000000000000000000000000000) { xAux >>= 128; result <<= 64; } if (xAux >= 0x10000000000000000) { xAux >>= 64; result <<= 32; } if (xAux >= 0x100000000) { xAux >>= 32; result <<= 16; } if (xAux >= 0x10000) { xAux >>= 16; result <<= 8; } if (xAux >= 0x100) { xAux >>= 8; result <<= 4; } if (xAux >= 0x10) { xAux >>= 4; result <<= 2; } if (xAux >= 0x8) { result <<= 1; } // The operations can never overflow because the result is max 2^127 when it enters this block. unchecked { result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; // Seven iterations should be enough uint256 roundedDownResult = x / result; return result >= roundedDownResult ? roundedDownResult : result; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` 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: * * - `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 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current 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); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; import { IPoolBorrowerActions } from './commons/IPoolBorrowerActions.sol'; import { IPoolLPActions } from './commons/IPoolLPActions.sol'; import { IPoolLenderActions } from './commons/IPoolLenderActions.sol'; import { IPoolKickerActions } from './commons/IPoolKickerActions.sol'; import { IPoolTakerActions } from './commons/IPoolTakerActions.sol'; import { IPoolSettlerActions } from './commons/IPoolSettlerActions.sol'; import { IPoolImmutables } from './commons/IPoolImmutables.sol'; import { IPoolState } from './commons/IPoolState.sol'; import { IPoolDerivedState } from './commons/IPoolDerivedState.sol'; import { IPoolEvents } from './commons/IPoolEvents.sol'; import { IPoolErrors } from './commons/IPoolErrors.sol'; import { IERC3156FlashLender } from './IERC3156FlashLender.sol'; /** * @title Base Pool Interface */ interface IPool is IPoolBorrowerActions, IPoolLPActions, IPoolLenderActions, IPoolKickerActions, IPoolTakerActions, IPoolSettlerActions, IPoolImmutables, IPoolState, IPoolDerivedState, IPoolEvents, IPoolErrors, IERC3156FlashLender { } /// @dev Pool type enum - `ERC20` and `ERC721` enum PoolType { ERC20, ERC721 } /// @dev `ERC20` token interface. interface IERC20Token { function balanceOf(address account) external view returns (uint256); function burn(uint256 amount) external; function decimals() external view returns (uint8); } /// @dev `ERC721` token interface. interface IERC721Token { function transferFrom( address from, address to, uint256 tokenId ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Pool Borrower Actions */ interface IPoolBorrowerActions { /** * @notice Called by fully collateralized borrowers to restamp the `Np to Tp ratio` of the loan (only if loan is fully collateralized and not in auction). * The reason for stamping the `Np to Tp ratio` on the loan is to provide some certainty to the borrower as to at what price they can expect to be liquidated. * This action can restamp only the loan of `msg.sender`. */ function stampLoan() external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Pool `LP` Actions */ interface IPoolLPActions { /** * @notice Called by `LP` owners to approve transfer of an amount of `LP` to a new owner. * @dev Intended for use by the `PositionManager` contract. * @param spender_ The new owner of the `LP`. * @param indexes_ Bucket indexes from where `LP` are transferred. * @param amounts_ The amounts of `LP` approved to transfer (`WAD` precision). */ function increaseLPAllowance( address spender_, uint256[] calldata indexes_, uint256[] calldata amounts_ ) external; /** * @notice Called by `LP` owners to decrease the amount of `LP` that can be spend by a new owner. * @dev Intended for use by the `PositionManager` contract. * @param spender_ The new owner of the `LP`. * @param indexes_ Bucket indexes from where `LP` are transferred. * @param amounts_ The amounts of `LP` disapproved to transfer (`WAD` precision). */ function decreaseLPAllowance( address spender_, uint256[] calldata indexes_, uint256[] calldata amounts_ ) external; /** * @notice Called by `LP` owners to decrease the amount of `LP` that can be spend by a new owner. * @param spender_ Address that is having it's allowance revoked. * @param indexes_ List of bucket index to remove the allowance from. */ function revokeLPAllowance( address spender_, uint256[] calldata indexes_ ) external; /** * @notice Called by `LP` owners to allow addresses that can transfer LP. * @dev Intended for use by the `PositionManager` contract. * @param transferors_ Addresses that are allowed to transfer `LP` to new owner. */ function approveLPTransferors( address[] calldata transferors_ ) external; /** * @notice Called by `LP` owners to revoke addresses that can transfer `LP`. * @dev Intended for use by the `PositionManager` contract. * @param transferors_ Addresses that are revoked to transfer `LP` to new owner. */ function revokeLPTransferors( address[] calldata transferors_ ) external; /** * @notice Called by `LP` owners to transfers their `LP` to a different address. `approveLpOwnership` needs to be run first. * @dev Used by `PositionManager.memorializePositions()`. * @param owner_ The original owner address of the position. * @param newOwner_ The new owner address of the position. * @param indexes_ Array of price buckets index at which `LP` were moved. */ function transferLP( address owner_, address newOwner_, uint256[] calldata indexes_ ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Pool Lender Actions */ interface IPoolLenderActions { /*********************************************/ /*** Quote/collateral management functions ***/ /*********************************************/ /** * @notice Called by lenders to add an amount of credit at a specified price bucket. * @param amount_ The amount of quote token to be added by a lender (`WAD` precision). * @param index_ The index of the bucket to which the quote tokens will be added. * @param expiry_ Timestamp after which this transaction will revert, preventing inclusion in a block with unfavorable price. * @return bucketLP_ The amount of `LP` changed for the added quote tokens (`WAD` precision). * @return addedAmount_ The amount of quote token added (`WAD` precision). */ function addQuoteToken( uint256 amount_, uint256 index_, uint256 expiry_ ) external returns (uint256 bucketLP_, uint256 addedAmount_); /** * @notice Called by lenders to move an amount of credit from a specified price bucket to another specified price bucket. * @param maxAmount_ The maximum amount of quote token to be moved by a lender (`WAD` precision). * @param fromIndex_ The bucket index from which the quote tokens will be removed. * @param toIndex_ The bucket index to which the quote tokens will be added. * @param expiry_ Timestamp after which this transaction will revert, preventing inclusion in a block with unfavorable price. * @return fromBucketLP_ The amount of `LP` moved out from bucket (`WAD` precision). * @return toBucketLP_ The amount of `LP` moved to destination bucket (`WAD` precision). * @return movedAmount_ The amount of quote token moved (`WAD` precision). */ function moveQuoteToken( uint256 maxAmount_, uint256 fromIndex_, uint256 toIndex_, uint256 expiry_ ) external returns (uint256 fromBucketLP_, uint256 toBucketLP_, uint256 movedAmount_); /** * @notice Called by lenders to claim collateral from a price bucket. * @param maxAmount_ The amount of collateral (`WAD` precision for `ERC20` pools, number of `NFT` tokens for `ERC721` pools) to claim. * @param index_ The bucket index from which collateral will be removed. * @return removedAmount_ The amount of collateral removed (`WAD` precision). * @return redeemedLP_ The amount of `LP` used for removing collateral amount (`WAD` precision). */ function removeCollateral( uint256 maxAmount_, uint256 index_ ) external returns (uint256 removedAmount_, uint256 redeemedLP_); /** * @notice Called by lenders to remove an amount of credit at a specified price bucket. * @param maxAmount_ The max amount of quote token to be removed by a lender (`WAD` precision). * @param index_ The bucket index from which quote tokens will be removed. * @return removedAmount_ The amount of quote token removed (`WAD` precision). * @return redeemedLP_ The amount of `LP` used for removing quote tokens amount (`WAD` precision). */ function removeQuoteToken( uint256 maxAmount_, uint256 index_ ) external returns (uint256 removedAmount_, uint256 redeemedLP_); /********************************/ /*** Interest update function ***/ /********************************/ /** * @notice Called by actors to update pool interest rate (can be updated only once in a `12` hours period of time). */ function updateInterest() external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Pool Kicker Actions */ interface IPoolKickerActions { /********************/ /*** Liquidations ***/ /********************/ /** * @notice Called by actors to initiate a liquidation. * @param borrower_ Identifies the loan to liquidate. * @param npLimitIndex_ Index of the lower bound of `NP` tolerated when kicking the auction. */ function kick( address borrower_, uint256 npLimitIndex_ ) external; /** * @notice Called by lenders to liquidate the top loan. * @param index_ The deposit index to use for kicking the top loan. * @param npLimitIndex_ Index of the lower bound of `NP` tolerated when kicking the auction. */ function lenderKick( uint256 index_, uint256 npLimitIndex_ ) external; /** * @notice Called by kickers to withdraw their auction bonds (the amount of quote tokens that are not locked in active auctions). * @param recipient_ Address to receive claimed bonds amount. * @param maxAmount_ The max amount to withdraw from auction bonds (`WAD` precision). Constrained by claimable amounts and liquidity. * @return withdrawnAmount_ The amount withdrawn (`WAD` precision). */ function withdrawBonds( address recipient_, uint256 maxAmount_ ) external returns (uint256 withdrawnAmount_); /***********************/ /*** Reserve Auction ***/ /***********************/ /** * @notice Called by actor to start a `Claimable Reserve Auction` (`CRA`). */ function kickReserveAuction() external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Pool Taker Actions */ interface IPoolTakerActions { /** * @notice Called by actors to use quote token to arb higher-priced deposit off the book. * @param borrowerAddress_ Address of the borower take is being called upon. * @param depositTake_ If `true` then the take will happen at an auction price equal with bucket price. Auction price is used otherwise. * @param index_ Index of a bucket, likely the `HPB`, in which collateral will be deposited. */ function bucketTake( address borrowerAddress_, bool depositTake_, uint256 index_ ) external; /** * @notice Called by actors to purchase collateral from the auction in exchange for quote token. * @param borrowerAddress_ Address of the borower take is being called upon. * @param maxAmount_ Max amount of collateral that will be taken from the auction (`WAD` precision for `ERC20` pools, max number of `NFT`s for `ERC721` pools). * @param callee_ Identifies where collateral should be sent and where quote token should be obtained. * @param data_ If provided, take will assume the callee implements `IERC*Taker`. Take will send collateral to * callee before passing this data to `IERC*Taker.atomicSwapCallback`. If not provided, * the callback function will not be invoked. * @return collateralTaken_ Amount of collateral taken from the auction (`WAD` precision for `ERC20` pools, max number of `NFT`s for `ERC721` pools). */ function take( address borrowerAddress_, uint256 maxAmount_, address callee_, bytes calldata data_ ) external returns (uint256 collateralTaken_); /***********************/ /*** Reserve Auction ***/ /***********************/ /** * @notice Purchases claimable reserves during a `CRA` using `Ajna` token. * @param maxAmount_ Maximum amount of quote token to purchase at the current auction price (`WAD` precision). * @return amount_ Actual amount of reserves taken (`WAD` precision). */ function takeReserves( uint256 maxAmount_ ) external returns (uint256 amount_); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Pool Settler Actions */ interface IPoolSettlerActions { /** * @notice Called by actors to settle an amount of debt in a completed liquidation. * @param borrowerAddress_ Address of the auctioned borrower. * @param maxDepth_ Measured from `HPB`, maximum number of buckets deep to settle debt. * @return collateralSettled_ Amount of collateral settled. * @return isBorrowerSettled_ True if all borrower's debt is settled. * @dev `maxDepth_` is used to prevent unbounded iteration clearing large liquidations. */ function settle( address borrowerAddress_, uint256 maxDepth_ ) external returns (uint256 collateralSettled_, bool isBorrowerSettled_); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Pool Immutables */ interface IPoolImmutables { /** * @notice Returns the type of the pool (`0` for `ERC20`, `1` for `ERC721`). */ function poolType() external pure returns (uint8); /** * @notice Returns the address of the pool's collateral token. */ function collateralAddress() external pure returns (address); /** * @notice Returns the address of the pool's quote token. */ function quoteTokenAddress() external pure returns (address); /** * @notice Returns the `quoteTokenScale` state variable. * @notice Token scale is also the minimum amount a lender may have in a bucket (dust amount). * @return The precision of the quote `ERC20` token based on decimals. */ function quoteTokenScale() external pure returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Pool Derived State */ interface IPoolDerivedState { /** * @notice Returns the exchange rate for a given bucket index. * @param index_ The bucket index. * @return exchangeRate_ Exchange rate of the bucket (`WAD` precision). */ function bucketExchangeRate( uint256 index_ ) external view returns (uint256 exchangeRate_); /** * @notice Returns the prefix sum of a given bucket. * @param index_ The bucket index. * @return The deposit up to given index (`WAD` precision). */ function depositUpToIndex( uint256 index_ ) external view returns (uint256); /** * @notice Returns the bucket index for a given debt amount. * @param debt_ The debt amount to calculate bucket index for (`WAD` precision). * @return Bucket index. */ function depositIndex( uint256 debt_ ) external view returns (uint256); /** * @notice Returns the total amount of quote tokens deposited in pool. * @return Total amount of deposited quote tokens (`WAD` precision). */ function depositSize() external view returns (uint256); /** * @notice Returns the meaningful actual utilization of the pool. * @return Deposit utilization (`WAD` precision). */ function depositUtilization() external view returns (uint256); /** * @notice Returns the scaling value of deposit at given index. * @param index_ Deposit index. * @return Deposit scaling (`WAD` precision). */ function depositScale( uint256 index_ ) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Pool Events */ interface IPoolEvents { /*********************/ /*** Lender events ***/ /*********************/ /** * @notice Emitted when lender adds quote token to the pool. * @param lender Recipient that added quote tokens. * @param index Index at which quote tokens were added. * @param amount Amount of quote tokens added to the pool (`WAD` precision). * @param lpAwarded Amount of `LP` awarded for the deposit (`WAD` precision). * @param lup `LUP` calculated after deposit. */ event AddQuoteToken( address indexed lender, uint256 indexed index, uint256 amount, uint256 lpAwarded, uint256 lup ); /** * @notice Emitted when lender moves quote token from a bucket price to another. * @param lender Recipient that moved quote tokens. * @param from Price bucket from which quote tokens were moved. * @param to Price bucket where quote tokens were moved. * @param amount Amount of quote tokens moved (`WAD` precision). * @param lpRedeemedFrom Amount of `LP` removed from the `from` bucket (`WAD` precision). * @param lpAwardedTo Amount of `LP` credited to the `to` bucket (`WAD` precision). * @param lup `LUP` calculated after removal. */ event MoveQuoteToken( address indexed lender, uint256 indexed from, uint256 indexed to, uint256 amount, uint256 lpRedeemedFrom, uint256 lpAwardedTo, uint256 lup ); /** * @notice Emitted when lender removes quote token from the pool. * @param lender Recipient that removed quote tokens. * @param index Index at which quote tokens were removed. * @param amount Amount of quote tokens removed from the pool (`WAD` precision). * @param lpRedeemed Amount of `LP` exchanged for quote token (`WAD` precision). * @param lup `LUP` calculated after removal. */ event RemoveQuoteToken( address indexed lender, uint256 indexed index, uint256 amount, uint256 lpRedeemed, uint256 lup ); /** * @notice Emitted when lender claims collateral from a bucket. * @param claimer Recipient that claimed collateral. * @param index Index at which collateral was claimed. * @param amount The amount of collateral (`WAD` precision for `ERC20` pools, number of `NFT` tokens for `ERC721` pools) transferred to the claimer. * @param lpRedeemed Amount of `LP` exchanged for quote token (`WAD` precision). */ event RemoveCollateral( address indexed claimer, uint256 indexed index, uint256 amount, uint256 lpRedeemed ); /***********************/ /*** Borrower events ***/ /***********************/ /** * @notice Emitted when borrower repays quote tokens to the pool and/or pulls collateral from the pool. * @param borrower `msg.sender` or on behalf of sender. * @param quoteRepaid Amount of quote tokens repaid to the pool (`WAD` precision). * @param collateralPulled The amount of collateral (`WAD` precision for `ERC20` pools, number of `NFT` tokens for `ERC721` pools) transferred to the claimer. * @param lup `LUP` after repay. */ event RepayDebt( address indexed borrower, uint256 quoteRepaid, uint256 collateralPulled, uint256 lup ); /**********************/ /*** Auction events ***/ /**********************/ /** * @notice Emitted when a liquidation is initiated. * @param borrower Identifies the loan being liquidated. * @param debt Debt the liquidation will attempt to cover (`WAD` precision). * @param collateral Amount of collateral up for liquidation (`WAD` precision for `ERC20` pools, number of `NFT` tokens for `ERC721` pools). * @param bond Bond amount locked by kicker (`WAD` precision). */ event Kick( address indexed borrower, uint256 debt, uint256 collateral, uint256 bond ); /** * @notice Emitted when kickers are withdrawing funds posted as auction bonds. * @param kicker The kicker withdrawing bonds. * @param reciever The address receiving withdrawn bond amount. * @param amount The bond amount that was withdrawn (`WAD` precision). */ event BondWithdrawn( address indexed kicker, address indexed reciever, uint256 amount ); /** * @notice Emitted when an actor uses quote token to arb higher-priced deposit off the book. * @param borrower Identifies the loan being liquidated. * @param index The index of the `Highest Price Bucket` used for this take. * @param amount Amount of quote token used to purchase collateral (`WAD` precision). * @param collateral Amount of collateral purchased with quote token (`WAD` precision). * @param bondChange Impact of this take to the liquidation bond (`WAD` precision). * @param isReward `True` if kicker was rewarded with `bondChange` amount, `false` if kicker was penalized. * @dev amount / collateral implies the auction price. */ event BucketTake( address indexed borrower, uint256 index, uint256 amount, uint256 collateral, uint256 bondChange, bool isReward ); /** * @notice Emitted when `LP` are awarded to a taker or kicker in a bucket take. * @param taker Actor who invoked the bucket take. * @param kicker Actor who started the auction. * @param lpAwardedTaker Amount of `LP` awarded to the taker (`WAD` precision). * @param lpAwardedKicker Amount of `LP` awarded to the actor who started the auction (`WAD` precision). */ event BucketTakeLPAwarded( address indexed taker, address indexed kicker, uint256 lpAwardedTaker, uint256 lpAwardedKicker ); /** * @notice Emitted when an actor uses quote token outside of the book to purchase collateral under liquidation. * @param borrower Identifies the loan being liquidated. * @param amount Amount of quote token used to purchase collateral (`WAD` precision). * @param collateral Amount of collateral purchased with quote token (for `ERC20` pool, `WAD` precision) or number of `NFT`s purchased (for `ERC721` pool). * @param bondChange Impact of this take to the liquidation bond (`WAD` precision). * @param isReward `True` if kicker was rewarded with `bondChange` amount, `false` if kicker was penalized. * @dev amount / collateral implies the auction price. */ event Take( address indexed borrower, uint256 amount, uint256 collateral, uint256 bondChange, bool isReward ); /** * @notice Emitted when an actor settles debt in a completed liquidation * @param borrower Identifies the loan under liquidation. * @param settledDebt Amount of pool debt settled in this transaction (`WAD` precision). * @dev When `amountRemaining_ == 0`, the auction has been completed cleared and removed from the queue. */ event Settle( address indexed borrower, uint256 settledDebt ); /** * @notice Emitted when auction is completed. * @param borrower Address of borrower that exits auction. * @param collateral Borrower's remaining collateral when auction completed (`WAD` precision). */ event AuctionSettle( address indexed borrower, uint256 collateral ); /** * @notice Emitted when `NFT` auction is completed. * @param borrower Address of borrower that exits auction. * @param collateral Borrower's remaining collateral when auction completed. * @param lp Amount of `LP` given to the borrower to compensate fractional collateral (if any, `WAD` precision). * @param index Index of the bucket with `LP` to compensate fractional collateral. */ event AuctionNFTSettle( address indexed borrower, uint256 collateral, uint256 lp, uint256 index ); /** * @notice Emitted when a `Claimaible Reserve Auction` is started. * @param claimableReservesRemaining Amount of claimable reserves which has not yet been taken (`WAD` precision). * @param auctionPrice Current price at which `1` quote token may be purchased, denominated in `Ajna`. * @param currentBurnEpoch Current burn epoch. */ event KickReserveAuction( uint256 claimableReservesRemaining, uint256 auctionPrice, uint256 currentBurnEpoch ); /** * @notice Emitted when a `Claimaible Reserve Auction` is taken. * @param claimableReservesRemaining Amount of claimable reserves which has not yet been taken (`WAD` precision). * @param auctionPrice Current price at which `1` quote token may be purchased, denominated in `Ajna`. * @param currentBurnEpoch Current burn epoch. */ event ReserveAuction( uint256 claimableReservesRemaining, uint256 auctionPrice, uint256 currentBurnEpoch ); /**************************/ /*** LP transfer events ***/ /**************************/ /** * @notice Emitted when owner increase the `LP` allowance of a spender at specified indexes with specified amounts. * @param owner `LP` owner. * @param spender Address approved to transfer `LP`. * @param indexes Bucket indexes of `LP` approved. * @param amounts `LP` amounts added (ordered by indexes, `WAD` precision). */ event IncreaseLPAllowance( address indexed owner, address indexed spender, uint256[] indexes, uint256[] amounts ); /** * @notice Emitted when owner decrease the `LP` allowance of a spender at specified indexes with specified amounts. * @param owner `LP` owner. * @param spender Address approved to transfer `LP`. * @param indexes Bucket indexes of `LP` approved. * @param amounts `LP` amounts removed (ordered by indexes, `WAD` precision). */ event DecreaseLPAllowance( address indexed owner, address indexed spender, uint256[] indexes, uint256[] amounts ); /** * @notice Emitted when lender removes the allowance of a spender for their `LP`. * @param owner `LP` owner. * @param spender Address that is having it's allowance revoked. * @param indexes List of bucket index to remove the allowance from. */ event RevokeLPAllowance( address indexed owner, address indexed spender, uint256[] indexes ); /** * @notice Emitted when lender whitelists addresses to accept `LP` from. * @param lender Recipient that approves new owner for `LP`. * @param transferors List of addresses that can transfer `LP` to lender. */ event ApproveLPTransferors( address indexed lender, address[] transferors ); /** * @notice Emitted when lender removes addresses from the `LP` transferors whitelist. * @param lender Recipient that approves new owner for `LP`. * @param transferors List of addresses that won't be able to transfer `LP` to lender anymore. */ event RevokeLPTransferors( address indexed lender, address[] transferors ); /** * @notice Emitted when a lender transfers their `LP` to a different address. * @dev Used by `PositionManager.memorializePositions()`. * @param owner The original owner address of the position. * @param newOwner The new owner address of the position. * @param indexes Array of price bucket indexes at which `LP` were transferred. * @param lp Amount of `LP` transferred (`WAD` precision). */ event TransferLP( address owner, address newOwner, uint256[] indexes, uint256 lp ); /**************************/ /*** Pool common events ***/ /**************************/ /** * @notice Emitted when `LP` are forfeited as a result of the bucket losing all assets. * @param index The index of the bucket. * @param lpForfeited Amount of `LP` forfeited by lenders (`WAD` precision). */ event BucketBankruptcy( uint256 indexed index, uint256 lpForfeited ); /** * @notice Emitted when a flashloan is taken from pool. * @param receiver The address receiving the flashloan. * @param token The address of token flashloaned from pool. * @param amount The amount of tokens flashloaned from pool (token precision). */ event Flashloan( address indexed receiver, address indexed token, uint256 amount ); /** * @notice Emitted when a loan `Np to Tp ratio` is restamped. * @param borrower Identifies the loan to update the `Np to Tp ratio`. */ event LoanStamped( address indexed borrower ); /** * @notice Emitted when pool interest rate is reset. This happens when `interest rate > 10%` and `debtEma < 5%` of `depositEma` * @param oldRate Old pool interest rate. * @param newRate New pool interest rate. */ event ResetInterestRate( uint256 oldRate, uint256 newRate ); /** * @notice Emitted when pool interest rate is updated. * @param oldRate Old pool interest rate. * @param newRate New pool interest rate. */ event UpdateInterestRate( uint256 oldRate, uint256 newRate ); /** * @notice Emitted when interest accural or update interest overflows. */ event InterestUpdateFailure(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Pool Errors. */ interface IPoolErrors { /**************************/ /*** Common Pool Errors ***/ /**************************/ /** * @notice Adding liquidity above current auction price. */ error AddAboveAuctionPrice(); /** * @notice The action cannot be executed on an active auction. */ error AuctionActive(); /** * @notice Attempted auction to clear doesn't meet conditions. */ error AuctionNotClearable(); /** * @notice Auction does not meet requirements to take liquidity. */ error AuctionNotTakeable(); /** * @notice Head auction should be cleared prior of executing this action. */ error AuctionNotCleared(); /** * @notice The auction price is greater than the arbed bucket price. */ error AuctionPriceGtBucketPrice(); /** * @notice Pool already initialized. */ error AlreadyInitialized(); /** * @notice Borrower is attempting to create or modify a loan such that their loan's quote token would be less than the pool's minimum debt amount. */ error AmountLTMinDebt(); /** * @notice Recipient of borrowed quote tokens doesn't match the caller of the `drawDebt` function. */ error BorrowerNotSender(); /** * @notice Borrower has a healthy over-collateralized position. */ error BorrowerOk(); /** * @notice Borrower is attempting to borrow more quote token than they have collateral for. */ error BorrowerUnderCollateralized(); /** * @notice Operation cannot be executed in the same block when bucket becomes insolvent. */ error BucketBankruptcyBlock(); /** * @notice User attempted to merge collateral from a lower price bucket into a higher price bucket. */ error CannotMergeToHigherPrice(); /** * @notice User attempted an operation which does not exceed the dust amount, or leaves behind less than the dust amount. */ error DustAmountNotExceeded(); /** * @notice Callback invoked by `flashLoan` function did not return the expected hash (see `ERC-3156` spec). */ error FlashloanCallbackFailed(); /** * @notice Balance of pool contract before flashloan is different than the balance after flashloan. */ error FlashloanIncorrectBalance(); /** * @notice Pool cannot facilitate a flashloan for the specified token address. */ error FlashloanUnavailableForToken(); /** * @notice User is attempting to move or pull more collateral than is available. */ error InsufficientCollateral(); /** * @notice Lender is attempting to move or remove more collateral they have claim to in the bucket. * @notice Lender is attempting to remove more collateral they have claim to in the bucket. * @notice Lender must have enough `LP` to claim the desired amount of quote from the bucket. */ error InsufficientLP(); /** * @notice Bucket must have more quote available in the bucket than the lender is attempting to claim. */ error InsufficientLiquidity(); /** * @notice When increasing / decreasing `LP` allowances indexes and amounts arrays parameters should have same length. */ error InvalidAllowancesInput(); /** * @notice When transferring `LP` between indices, the new index must be a valid index. */ error InvalidIndex(); /** * @notice The amount used for performed action should be greater than `0`. */ error InvalidAmount(); /** * @notice Borrower is attempting to borrow more quote token than is available before the supplied `limitIndex`. */ error LimitIndexExceeded(); /** * @notice When moving quote token `HTP` must stay below `LUP`. * @notice When removing quote token `HTP` must stay below `LUP`. */ error LUPBelowHTP(); /** * @notice From index and to index arguments to move are the same. */ error MoveToSameIndex(); /** * @notice Owner of the `LP` must have approved the new owner prior to transfer. */ error NoAllowance(); /** * @notice Actor is attempting to take or clear an inactive auction. */ error NoAuction(); /** * @notice No pool reserves are claimable. */ error NoReserves(); /** * @notice Actor is attempting to take or clear an inactive reserves auction. */ error NoReservesAuction(); /** * @notice Lender must have non-zero `LP` when attemptign to remove quote token from the pool. */ error NoClaim(); /** * @notice Borrower has no debt to liquidate. * @notice Borrower is attempting to repay when they have no outstanding debt. */ error NoDebt(); /** * @notice Actor is attempting to kick with bucket price below the `LUP`. */ error PriceBelowLUP(); /** * @notice Lender is attempting to remove quote tokens from a bucket that exists above active auction debt from top-of-book downward. */ error RemoveDepositLockedByAuctionDebt(); /** * @notice User attempted to kick off a new auction less than `2` weeks since the last auction completed. */ error ReserveAuctionTooSoon(); /** * @notice Current block timestamp has reached or exceeded a user-provided expiration. */ error TransactionExpired(); /** * @notice The address that transfer `LP` is not approved by the `LP` receiving address. */ error TransferorNotApproved(); /** * @notice Owner of the `LP` attemps to transfer `LP` to same address. */ error TransferToSameOwner(); /** * @notice The DebtToCollateral of the loan to be inserted in loans heap is zero. */ error ZeroDebtToCollateral(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; import { IERC3156FlashBorrower } from "./IERC3156FlashBorrower.sol"; interface IERC3156FlashLender { /** * @dev The amount of currency available to be lent. * @param token_ The loan currency. * @return The amount of `token` that can be borrowed (token precision). */ function maxFlashLoan( address token_ ) external view returns (uint256); /** * @dev The fee to be charged for a given loan. * @param token_ The loan currency. * @param amount_ The amount of tokens lent (token precision). * @return The amount of `token` to be charged for the loan (token precision), on top of the returned principal . */ function flashFee( address token_, uint256 amount_ ) external view returns (uint256); /** * @dev Initiate a flash loan. * @param receiver_ The receiver of the tokens in the loan, and the receiver of the callback. * @param token_ The loan currency. * @param amount_ The amount of tokens lent (token precision). * @param data_ Arbitrary data structure, intended to contain user-defined parameters. * @return `True` when successful flashloan, `false` otherwise. */ function flashLoan( IERC3156FlashBorrower receiver_, address token_, uint256 amount_, bytes calldata data_ ) external returns (bool); }
{ "remappings": [ "@solmate/=lib/solmate/src/", "@std/=lib/forge-std/src/", "@clones/=lib/clones-with-immutable-args/src/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@prb-math/=lib/prb-math/", "@base64-sol/=lib/base64/", "src/=src/", "base64/=lib/base64/", "clones-with-immutable-args/=lib/clones-with-immutable-args/src/", "ds-test/=lib/clones-with-immutable-args/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "prb-math/=lib/prb-math/contracts/" ], "optimizer": { "enabled": true, "runs": 0 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": { "src/libraries/external/BorrowerActions.sol": { "BorrowerActions": "0x37ed1d5d903adddda4fcc6d003b840c883d05402" }, "src/libraries/external/KickerActions.sol": { "KickerActions": "0xaf983b52aec0f6e127ddd51ce3367552d7916387" }, "src/libraries/external/LPActions.sol": { "LPActions": "0xac8892dd81ee0fec9c11ecf6ef3bd1a773d003fb" }, "src/libraries/external/LenderActions.sol": { "LenderActions": "0xdce7fd455e1a65b40186292657e6231f87d81c49" }, "src/libraries/external/PoolCommons.sol": { "PoolCommons": "0xe88aaf46c9124b7b08c2dcc2505429ce72979648" }, "src/libraries/external/PositionNFTSVG.sol": { "PositionNFTSVG": "0x83fcb77b91288173175a4ac70f848d57ff95a9dd" }, "src/libraries/external/SettlerActions.sol": { "SettlerActions": "0x4418b6a45d785b85e87c022d99b0ff9e267268fe" }, "src/libraries/external/TakerActions.sol": { "TakerActions": "0x9c09a67a622650037fe70f21a5f6770a363009e1" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"BucketPriceOutOfBounds","type":"error"},{"inputs":[],"name":"FlashloanCallbackFailed","type":"error"},{"inputs":[],"name":"FlashloanIncorrectBalance","type":"error"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__CeilOverflow","type":"error"},{"inputs":[],"name":"PRBMathSD59x18__DivInputTooSmall","type":"error"},{"inputs":[{"internalType":"uint256","name":"rAbs","type":"uint256"}],"name":"PRBMathSD59x18__DivOverflow","type":"error"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__Exp2InputTooBig","type":"error"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__ExpInputTooBig","type":"error"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__LogInputTooSmall","type":"error"},{"inputs":[],"name":"PRBMathSD59x18__MulInputTooSmall","type":"error"},{"inputs":[{"internalType":"uint256","name":"rAbs","type":"uint256"}],"name":"PRBMathSD59x18__MulOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"PRBMathUD60x18__Exp2InputTooBig","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"PRBMathUD60x18__ExpInputTooBig","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"PRBMathUD60x18__LogInputTooSmall","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"}],"name":"PRBMath__MulDivFixedPointOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath__MulDivOverflow","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Flashloan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"ResetInterestRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"UpdateInterestRate","type":"event"},{"inputs":[{"components":[{"internalType":"uint256","name":"pledgedCollateral","type":"uint256"},{"internalType":"uint256","name":"t0DebtInAuction","type":"uint256"},{"internalType":"uint256","name":"t0Debt","type":"uint256"}],"internalType":"struct PoolBalancesState","name":"poolBalances_","type":"tuple"},{"components":[{"internalType":"uint208","name":"inflator","type":"uint208"},{"internalType":"uint48","name":"inflatorUpdate","type":"uint48"}],"internalType":"struct InflatorState","name":"inflatorState_","type":"tuple"},{"components":[{"internalType":"uint208","name":"interestRate","type":"uint208"},{"internalType":"uint48","name":"interestRateUpdate","type":"uint48"},{"internalType":"uint256","name":"debt","type":"uint256"},{"internalType":"uint256","name":"meaningfulDeposit","type":"uint256"},{"internalType":"uint256","name":"t0Debt2ToCollateral","type":"uint256"},{"internalType":"uint256","name":"debtCol","type":"uint256"},{"internalType":"uint256","name":"lupt0Debt","type":"uint256"}],"internalType":"struct InterestState","name":"interestState_","type":"tuple"}],"name":"debtInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mau_","type":"uint256"}],"name":"lenderInterestMargin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"inflator_","type":"uint256"},{"internalType":"uint256","name":"inflatorUpdate","type":"uint256"},{"internalType":"uint256","name":"interestRate_","type":"uint256"}],"name":"pendingInflator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"interestRate_","type":"uint256"},{"internalType":"uint256","name":"elapsed_","type":"uint256"}],"name":"pendingInterestFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}]
Contract Creation Code
612d0e61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100825760003560e01c80630cbcb4cd146100875780635676e1ff146100ad57806378792ff1146100cf5780639b5bef86146100e2578063d3f2b14a14610110578063edf6fdf614610130578063f6eb5f8514610143578063fc99bab014610176575b600080fd5b61009a6100953660046124a4565b610189565b6040519081526020015b60405180910390f35b8180156100b957600080fd5b506100cd6100c836600461255a565b6101b5565b005b61009a6100dd36600461261e565b610669565b8180156100ee57600080fd5b506101026100fd36600461264a565b61069a565b6040516100a492919061269f565b81801561011c57600080fd5b506100cd61012b3660046126c2565b6107ec565b61009a61013e366004612760565b610a26565b610156610151366004612843565b610a31565b6040805194855260208501939093529183015260608201526080016100a4565b61009a610184366004612760565b610aaf565b60006101ac6301e1338061019d848661291c565b6101a79190612949565b610ac3565b90505b92915050565b61022e604051806101e001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b84548152600185015460208083019190915260028601546040808401919091526003808801546060850152600488015461012085015288015460808401528401519084015161027d919061295d565b6101c0820181905260a08401516102949190610b1e565b8160c00181815250506102c86102be858560400151846101c001518760a001518660800151610b52565b8260c00151610bde565b8160a00181815250506102e38360a001518260800151610b1e565b60e08201526101c08101516102f9908390610b1e565b61010082015261012081015142146104f3578061012001516000036103435760c0810151815260a0810151602082015260e0810151604082015261010081015160608201526104ca565b61035f81610120015142610357919061295d565b610e10610bf5565b61014082018190526103839061037e9066cd367959873bd81990610c15565b610cda565b6101608201526101408101516103a69061037e90661d50ecc3a59ad51990610c15565b6101808201526101608101516103d2906103c890670de0b6b3a7640000612970565b8760010154610c15565b6103e58261016001518360000151610c15565b6103ef9190612997565b81526101608101516104179061040d90670de0b6b3a7640000612970565b8760020154610c15565b61042a8261016001518360200151610c15565b6104349190612997565b602082015261018081015161045f9061045590670de0b6b3a7640000612970565b8760040154610c15565b6104728261018001518360400151610c15565b61047c9190612997565b60408201526101808101516104a79061049d90670de0b6b3a7640000612970565b8760050154610c15565b6104ba8261018001518360600151610c15565b6104c49190612997565b60608201525b805185556020810151600186015560408101516002860155606081015160038601554260048601555b67016345785d8a00008360e00151118015610522575061051e816020015166b1a2bc2ec50000610b1e565b8151105b156105845767016345785d8a0000600160d01b4265ffffffffffff16028117875560e08401516040517f20ae1d4a2e8d297f3820670c20fc79531e31643d4b201892680e7df3c4ab159992610577929161269f565b60405180910390a1610637565b855461a8c0906105a390600160d01b900465ffffffffffff164261295d565b1115610637576105c6838260000151836020015184604001518560600151610d4a565b6101a0820181905260e084015114610637576101a081015165ffffffffffff4216600160d01b026001600160d01b03821617875560e08401516040517f2463616ef8e6f9bddf00e4964b853ad9050f87cd3c73985d2ee6b6c8a83369919261062e929161269f565b60405180910390a15b60c0810151600187015560a0810151600287015560e08101516004870155610100015160059095019490945550505050565b60006106908461068b6301e13380610681874261295d565b61019d908761291c565b610b1e565b90505b9392505050565b600080806106b46301e1338061019d8660e08a013561291c565b90506106c48660a0013582610b1e565b925060006106d6868860a00135610edd565b905060006b033f4a75fb6ff29166751a4b8211156106f657506001610718565b64173eb4c80a82101561070c5750611cdc610718565b61071582610efa565b90505b60006107288a8a60600135610fc4565b905081811115610736578091505b60006107428b84610fda565b905080156107dd576107866107676107628e600001548f600101546110e5565b6110f7565b61068b61077c670de0b6b3a76400008961295d565b8d60600135610b1e565b95506000670de0b6b3a76400006107c46107a089856111a1565b6107bf6107b5670de0b6b3a76400008b61295d565b61068b600a6111b6565b6111ca565b6107ce91906129bf565b90506107db8c85836111da565b505b50505050509550959350505050565b6040516370a0823160e01b815284906000906001600160a01b038316906370a082319061081d9030906004016129d2565b602060405180830381865afa15801561083a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085e91906129e6565b90506108746001600160a01b038316888761137d565b6040516323e30c8b60e01b81527f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9906001600160a01b038916906323e30c8b906108cd9033908b908b906000908c908c906004016129ff565b6020604051808303816000875af11580156108ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091091906129e6565b1461092e5760405163f594248f60e01b815260040160405180910390fd5b6109436001600160a01b0383168830886113e5565b6040516370a0823160e01b815281906001600160a01b038416906370a08231906109719030906004016129d2565b602060405180830381865afa15801561098e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b291906129e6565b146109d0576040516370fc723360e01b815260040160405180910390fd5b856001600160a01b0316876001600160a01b03167f6b15284fe89dbd5c436c2e0b06b1bf72e3a0a8e96d1b4a2abd61dfae2d7849a687604051610a1591815260200190565b60405180910390a350505050505050565b60006101af826110f7565b600080600080600087604001519050600087600001516001600160d01b03169050610a7f82610a7a838b6020015165ffffffffffff168b600001516001600160d01b0316610669565b611423565b610a898383611423565b610a978b6020015184611423565b89608001519550955095509550505093509350935093565b60006101af826000015483600101546110e5565b6000680736ea4425c11ac6318210610af65760405163062bb40d60e31b8152600481018390526024015b60405180910390fd5b6714057b7ef767814f8202610693670de0b6b3a76400006706f05b59d3b2000083010461144f565b6000670de0b6b3a7640000610b34600282612949565b610b3e848661291c565b610b4891906129bf565b6101ac9190612949565b600080610b60858585611495565b905080600003610b78576120008701545b9150610bbb565b6b033f4a75fb6ff29166751a4b8110610b945760009150610bbb565b64173eb4c80a8110610bb257610b7187610bad83610efa565b610fda565b61200087015491505b610bc9826107bf8887610b1e565b610bd3908361295d565b979650505050505050565b600081831015610bee57816101ac565b5090919050565b600081610c03600282612949565b610b3e670de0b6b3a76400008661291c565b6000600160ff1b831480610c2c5750600160ff1b82145b15610c4a57604051630d01a11b60e21b815260040160405180910390fd5b60008060008512610c5b5784610c60565b846000035b915060008412610c705783610c75565b836000035b90506000610c8383836114c2565b90506001600160ff1b03811115610cb05760405163bf79e8d960e01b815260048101829052602401610aed565b600019808713908613808218600114610cc95782610cce565b826000035b98975050505050505050565b600068023f2fa8f6da5b9d3119821215610cf657506000919050565b680736ea4425c11ac6318212610d22576040516399bb754160e01b815260048101839052602401610aed565b6714057b7ef767814f8202610693670de0b6b3a76400006706f05b59d3b20000830105611588565b60008060008760600151600014610d8f57610d6587876110e5565b9150670de0b6b3a7640000610d82670e27c49886e6000084612a5b565b610d8c9190612a8b565b90505b600084600003610da757670de0b6b3a7640000610db1565b610db18686610bf5565b60e08a015194509050670de0b6b3a76400006002633b9aca0082610dd58686612997565b610ddf9190612970565b610de99190612a8b565b610df39190612bee565b610dfd9190612970565b610e078383612970565b610e12906004612a5b565b1215610e3557610e2e8960e00151670f43fc2c04ee0000610b1e565b9350610eb3565b6002633b9aca00670de0b6b3a7640000610e4f8685612997565b610e599190612970565b610e639190612a8b565b610e6d9190612bee565b610e7f90670de0b6b3a7640000612970565b610e898483612970565b610e94906004612a5b565b1315610eb357610eb08960e00151670c7d713b49da0000610b1e565b93505b610ed0673782dace9d9000006107bf66038d7ea4c6800087610bde565b9998505050505050505050565b60006101ac610eec8484610b1e565b670e6ed27d66680000610b1e565b600064173eb4c80a821080610f1a57506b033f4a75fb6ff29166751a4b82115b15610f3857604051635665ba4560e11b815260040160405180910390fd5b6000610f5c610f468461160c565b610f57670df27a2cdf44800061160c565b6116f0565b90506000610f69826117b6565b9050600082128015610f8b57506706f05b59d3b20000610f898383612970565b135b15610fae57610fa6670de0b6b3a7640000820561103d612970565b949350505050565b610fa6670de0b6b3a7640000820561103c612970565b6000610fd08383611824565b5090949350505050565b6000610fe582612bfd565b9150670de0b6b3a7640000612000600080610fff86611914565b905060005b8184106110da5761101584846129bf565b90506120008111611004576000886120010182612001811061103957611039612c16565b01549050878516156110ba5760008983612001811061105a5761105a612c16565b0154905081600003611075576110708782610b1e565b611097565b611097611082838961291c565b826a0c097ce7bc90715b34b9f160241b611933565b6110a190896129bf565b97508294508885036110b45750506110da565b506110cd565b80156110cd576110ca86826119e2565b95505b600185901c945050611004565b505050505092915050565b600081156101af576101ac8383610bf5565b60008061110c83670de0b6b3a76400006111ca565b61111990620f424061291c565b61112d9069d3c21bcecceda100000061295d565b9050670de0b6b3a764000081101561114f5750670de0b6b3a764000092915050565b6000611163826704a03ce68d2155566119f7565b905061118961117a82670214e8348c4f0000610b1e565b68056bc75e2d63100000610bf5565b610fa690670de0b6b3a764000061295d565b50919050565b600081610b48670de0b6b3a76400008561291c565b60006101af670de0b6b3a76400008361291c565b600081831115610bee57816101ac565b6111e382612bfd565b91506000806000806111f486611914565b90505b612000811161137457808616156112e5578686612001811061121b5761121b612c16565b01549250866120010186612001811061123657611236612c16565b01549150811561129857600061124c8684610b1e565b90506112588385610b1e565b6112628286610b1e565b61126c919061295d565b61127690866129bf565b945080886120010188612001811061129057611290612c16565b0155506112d4565b826112a38685610b1e565b6112ad919061295d565b6112b790856129bf565b93508487612001018761200181106112d1576112d1612c16565b01555b6112de818761295d565b955061136c565b60006112f182886129bf565b9050848882612001811061130757611307612c16565b01600082825461131791906129bf565b9250508190559350876120010181612001811061133657611336612c16565b01549250821561136a5761135361134d868661295d565b84610b1e565b61135d8585610b1e565b611367919061295d565b94505b505b60011b6111f7565b50505050505050565b6040516001600160a01b0383166024820152604481018290526113e090849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611a39565b505050565b6040516001600160a01b038085166024830152831660448201526064810182905261141d9085906323b872dd60e01b906084016113a9565b50505050565b6000670de0b6b3a764000060018161143b858761291c565b61144591906129bf565b610b48919061295d565b6000680a688906bd8b000000821061147d57604051634a4f26f160e01b815260048101839052602401610aed565b670de0b6b3a7640000604083901b0461069381611b0b565b600083156114b8576114b36114ad610eec8585610b1e565b85610bf5565b610690565b5060009392505050565b60008080600019848609848602925082811083820303915050670de0b6b3a764000081106115065760405163698d9a0160e11b815260048101829052602401610aed565b600080670de0b6b3a764000086880991506706f05b59d3b1ffff82119050826000036115445780670de0b6b3a76400008504019450505050506101af565b620400008285030493909111909103600160ee1b02919091177faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106690201905092915050565b6000808212156115db5768033dd1780914b97114198212156115ac57506000919050565b6115b882600003611588565b6a0c097ce7bc90715b34b9f160241b816115d4576115d4612933565b0592915050565b680a688906bd8b000000821261147d5760405163e69458f960e01b815260048101839052602401610aed565b919050565b60008082136116315760405163309fa7dd60e11b815260048101839052602401610aed565b6000670de0b6b3a7640000831261164a57506001611663565b6000199050826a0c097ce7bc90715b34b9f160241b0492505b6000611678670de0b6b3a7640000850561219d565b670de0b6b3a764000081029350905083811d670de0b6b3a763ffff1981016116a257505002919050565b6706f05b59d3b200005b60008113156116e757670de0b6b3a7640000828002059150671bc16d674ec8000082126116df579384019360019190911d905b60011d6116ac565b50505002919050565b6000600160ff1b8314806117075750600160ff1b82145b156117255760405163b3c754a360e01b815260040160405180910390fd5b60008060008512611736578461173b565b846000035b91506000841261174b5783611750565b836000035b9050600061176783670de0b6b3a76400008461227b565b90506001600160ff1b0381111561179457604051637cb4bef560e01b815260048101829052602401610aed565b6000198087139086138082186001146117ad5782610cce565b610cce83612c2c565b6000670afdc366fbc00000600160ff1b038213156117ea57604051635399a28560e11b815260048101839052602401610aed565b670de0b6b3a7640000820760008190036118065782915061119b565b8083039150600083131561119b5750670de0b6b3a764000001919050565b60008080611000670de0b6b3a764000082808080805b86156119065761184a878b6129bf565b93508b84612001811061185f5761185f612c16565b015492508b6120010184612001811061187a5761187a612c16565b0154915081600003611895576118908684610b1e565b6118b7565b6118b76118a2838861291c565b846a0c097ce7bc90715b34b9f160241b611933565b6118c190866129bf565b90508a8110156118e057611cdc84116118db578399508094505b6118fa565b81156118f3576118f086836119e2565b95505b8098508597505b600187901c965061183a565b505050505050509250925092565b600081156116075761192b600019831860016129bf565b909116919050565b600080806000198587098587029250828110838203039150508060000361196d5783828161196357611963612933565b0492505050610693565b80841161197957600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000670de0b6b3a7640000610b48838561291c565b600082600003611a1f578115611a0e576000611a18565b670de0b6b3a76400005b90506101af565b6101ac611a34611a2e856122cf565b84612385565b61144f565b6000611a8e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166123919092919063ffffffff16565b8051909150156113e05780806020019051810190611aac9190612c48565b6113e05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610aed565b600160bf1b6001603f1b821615611b2b5768016a09e667f3bcc9090260401c5b6001603e1b821615611b46576801306fe0a31b7152df0260401c5b6001603d1b821615611b61576801172b83c7d517adce0260401c5b6001603c1b821615611b7c5768010b5586cf9890f62a0260401c5b6001603b1b821615611b97576801059b0d31585743ae0260401c5b6001603a1b821615611bb257680102c9a3e778060ee70260401c5b600160391b821615611bcd5768010163da9fb33356d80260401c5b600160381b821615611be857680100b1afa5abcbed610260401c5b600160371b821615611c035768010058c86da1c09ea20260401c5b600160361b821615611c1e576801002c605e2e8cec500260401c5b600160351b821615611c3957680100162f3904051fa10260401c5b600160341b821615611c54576801000b175effdc76ba0260401c5b600160331b821615611c6f57680100058ba01fb9f96d0260401c5b600160321b821615611c8a5768010002c5cc37da94920260401c5b600160311b821615611ca5576801000162e525ee05470260401c5b600160301b821615611cc05768010000b17255775c040260401c5b6001602f1b821615611cdb576801000058b91b5bc9ae0260401c5b6001602e1b821615611cf657680100002c5c89d5ec6d0260401c5b6001602d1b821615611d115768010000162e43f4f8310260401c5b6001602c1b821615611d2c57680100000b1721bcfc9a0260401c5b6001602b1b821615611d475768010000058b90cf1e6e0260401c5b6001602a1b821615611d62576801000002c5c863b73f0260401c5b600160291b821615611d7d57680100000162e430e5a20260401c5b600160281b821615611d98576801000000b1721835510260401c5b600160271b821615611db357680100000058b90c0b490260401c5b600160261b821615611dce5768010000002c5c8601cc0260401c5b600160251b821615611de9576801000000162e42fff00260401c5b600160241b821615611e045768010000000b17217fbb0260401c5b600160231b821615611e1f576801000000058b90bfce0260401c5b600160221b821615611e3a57680100000002c5c85fe30260401c5b600160211b821615611e555768010000000162e42ff10260401c5b600160201b821615611e7057680100000000b17217f80260401c5b6380000000821615611e8b5768010000000058b90bfc0260401c5b6340000000821615611ea6576801000000002c5c85fe0260401c5b6320000000821615611ec157680100000000162e42ff0260401c5b6310000000821615611edc576801000000000b17217f0260401c5b6308000000821615611ef757680100000000058b90c00260401c5b6304000000821615611f125768010000000002c5c8600260401c5b6302000000821615611f2d576801000000000162e4300260401c5b6301000000821615611f485768010000000000b172180260401c5b62800000821615611f62576801000000000058b90c0260401c5b62400000821615611f7c57680100000000002c5c860260401c5b62200000821615611f965768010000000000162e430260401c5b62100000821615611fb057680100000000000b17210260401c5b62080000821615611fca5768010000000000058b910260401c5b62040000821615611fe4576801000000000002c5c80260401c5b62020000821615611ffe57680100000000000162e40260401c5b620100008216156120175761b172600160401b010260401c5b61800082161561202f576158b9600160401b010260401c5b61400082161561204757612c5d600160401b010260401c5b61200082161561205f5761162e600160401b010260401c5b61100082161561207757610b17600160401b010260401c5b61080082161561208f5761058c600160401b010260401c5b6104008216156120a7576102c6600160401b010260401c5b6102008216156120bf57610163600160401b010260401c5b6101008216156120d65760b1600160401b010260401c5b60808216156120ec576059600160401b010260401c5b604082161561210257602c600160401b010260401c5b6020821615612118576016600160401b010260401c5b601082161561212e57600b600160401b010260401c5b6008821615612144576006600160401b010260401c5b600482161561215a576003600160401b010260401c5b6002821615612170576001600160401b010260401c5b6001821615612186576001600160401b010260401c5b670de0b6b3a76400000260409190911c60bf031c90565b6000600160801b82106121bd57608091821c916121ba90826129bf565b90505b600160401b82106121db57604091821c916121d890826129bf565b90505b600160201b82106121f957602091821c916121f690826129bf565b90505b62010000821061221657601091821c9161221390826129bf565b90505b610100821061223257600891821c9161222f90826129bf565b90505b6010821061224d57600491821c9161224a90826129bf565b90505b6004821061226857600291821c9161226590826129bf565b90505b60028210611607576101af6001826129bf565b60008080600019858709858702925082811083820303915050806000036122ab5783828161196357611963612933565b838110611979578084604051631dcf306360e21b8152600401610aed92919061269f565b6000670de0b6b3a76400008210156122fd57604051633621413760e21b815260048101839052602401610aed565b6000612312670de0b6b3a7640000840461219d565b670de0b6b3a764000081029250905082811c670de0b6b3a763ffff19810161233b575050919050565b6706f05b59d3b200005b801561237d57670de0b6b3a7640000828002049150671bc16d674ec800008210612375579283019260019190911c905b60011c612345565b505050919050565b60006101ac83836114c2565b6060610690848460008585600080866001600160a01b031685876040516123b89190612c89565b60006040518083038185875af1925050503d80600081146123f5576040519150601f19603f3d011682016040523d82523d6000602084013e6123fa565b606091505b5091509150610bd3878383876060831561247557825160000361246e576001600160a01b0385163b61246e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610aed565b5081610fa6565b610fa6838381511561248a5781518083602001fd5b8060405162461bcd60e51b8152600401610aed9190612ca5565b600080604083850312156124b757600080fd5b50508035926020909101359150565b60405161012081016001600160401b03811182821017156124f757634e487b7160e01b600052604160045260246000fd5b60405290565b604080519081016001600160401b03811182821017156124f757634e487b7160e01b600052604160045260246000fd5b803560ff8116811461160757600080fd5b801515811461254c57600080fd5b50565b80356116078161253e565b60008060008060008587036101a081121561257457600080fd5b86359550602087013594506040870135935061012080605f198301121561259a57600080fd5b6125a26124c6565b91506125b06060890161252d565b82526080880135602083015260a0880135604083015260c0880135606083015260e088013560808301526101008089013560a08401526125f1828a0161254f565b60c084015261014089013560e0840152610160890135908301525094979396509194610180013592915050565b60008060006060848603121561263357600080fd5b505081359360208301359350604090920135919050565b60008060008060008587036101a081121561266457600080fd5b8635955060208701359450610120603f198201121561268257600080fd5b509396929550505060408301926101608101359250610180013590565b918252602082015260400190565b6001600160a01b038116811461254c57600080fd5b6000806000806000608086880312156126da57600080fd5b85356126e5816126ad565b945060208601356126f5816126ad565b93506040860135925060608601356001600160401b038082111561271857600080fd5b818801915088601f83011261272c57600080fd5b81358181111561273b57600080fd5b89602082850101111561274d57600080fd5b9699959850939650602001949392505050565b60006020828403121561277257600080fd5b5035919050565b80356001600160d01b038116811461160757600080fd5b803565ffffffffffff8116811461160757600080fd5b600060e082840312156127b857600080fd5b60405160e081016001600160401b03811182821017156127e857634e487b7160e01b600052604160045260246000fd5b6040529050806127f783612779565b815261280560208401612790565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c08201525092915050565b600080600083850361018081121561285a57600080fd5b606081121561286857600080fd5b604051606081016001600160401b038111828210171561289857634e487b7160e01b600052604160045260246000fd5b604090815286358252602080880135908301528681013582820152909450605f19820112156128c657600080fd5b506128cf6124fd565b6128db60608601612779565b81526128e960808601612790565b602082015291506128fd8560a086016127a6565b90509250925092565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176101af576101af612906565b634e487b7160e01b600052601260045260246000fd5b60008261295857612958612933565b500490565b818103818111156101af576101af612906565b818103600083128015838313168383128216171561299057612990612906565b5092915050565b80820182811260008312801582168215821617156129b7576129b7612906565b505092915050565b808201808211156101af576101af612906565b6001600160a01b0391909116815260200190565b6000602082840312156129f857600080fd5b5051919050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b80820260008212600160ff1b84141615612a7757612a77612906565b81810583148215176101af576101af612906565b600082612a9a57612a9a612933565b600160ff1b821460001984141615612ab457612ab4612906565b500590565b80825b6001808611612acb5750612afe565b6001600160ff1b03829004821115612ae557612ae5612906565b80861615612af257918102915b9490941c938002612abc565b935093915050565b6000828015612b1c5760018114612b2657612b2f565b60019150506101af565b829150506101af565b5081612b3d575060006101af565b50600160008213808214612b56578015612b7557612b8f565b6001600160ff1b03839004831115612b7057612b70612906565b612b8f565b6001600160ff1b03839005831215612b8f57612b8f612906565b5080831615612b9b5750805b612bab8360011c83840283612ab9565b600082136001600160ff1b0382900483111615612bca57612bca612906565b60008212600160ff1b82900583121615612be657612be6612906565b029392505050565b60006101ac60ff841683612b06565b600060018201612c0f57612c0f612906565b5060010190565b634e487b7160e01b600052603260045260246000fd5b6000600160ff1b8201612c4157612c41612906565b5060000390565b600060208284031215612c5a57600080fd5b81516106938161253e565b60005b83811015612c80578181015183820152602001612c68565b50506000910152565b60008251612c9b818460208701612c65565b9190910192915050565b6020815260008251806020840152612cc4816040850160208701612c65565b601f01601f1916919091016040019291505056fea2646970667358221220355b992d4aaf3160c026285d382b9ee30781a9e373d5f9e4fc0ca9be8f602cf864736f6c63430008120033
Deployed Bytecode
0x73e88aaf46c9124b7b08c2dcc2505429ce7297964830146080604052600436106100825760003560e01c80630cbcb4cd146100875780635676e1ff146100ad57806378792ff1146100cf5780639b5bef86146100e2578063d3f2b14a14610110578063edf6fdf614610130578063f6eb5f8514610143578063fc99bab014610176575b600080fd5b61009a6100953660046124a4565b610189565b6040519081526020015b60405180910390f35b8180156100b957600080fd5b506100cd6100c836600461255a565b6101b5565b005b61009a6100dd36600461261e565b610669565b8180156100ee57600080fd5b506101026100fd36600461264a565b61069a565b6040516100a492919061269f565b81801561011c57600080fd5b506100cd61012b3660046126c2565b6107ec565b61009a61013e366004612760565b610a26565b610156610151366004612843565b610a31565b6040805194855260208501939093529183015260608201526080016100a4565b61009a610184366004612760565b610aaf565b60006101ac6301e1338061019d848661291c565b6101a79190612949565b610ac3565b90505b92915050565b61022e604051806101e001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b84548152600185015460208083019190915260028601546040808401919091526003808801546060850152600488015461012085015288015460808401528401519084015161027d919061295d565b6101c0820181905260a08401516102949190610b1e565b8160c00181815250506102c86102be858560400151846101c001518760a001518660800151610b52565b8260c00151610bde565b8160a00181815250506102e38360a001518260800151610b1e565b60e08201526101c08101516102f9908390610b1e565b61010082015261012081015142146104f3578061012001516000036103435760c0810151815260a0810151602082015260e0810151604082015261010081015160608201526104ca565b61035f81610120015142610357919061295d565b610e10610bf5565b61014082018190526103839061037e9066cd367959873bd81990610c15565b610cda565b6101608201526101408101516103a69061037e90661d50ecc3a59ad51990610c15565b6101808201526101608101516103d2906103c890670de0b6b3a7640000612970565b8760010154610c15565b6103e58261016001518360000151610c15565b6103ef9190612997565b81526101608101516104179061040d90670de0b6b3a7640000612970565b8760020154610c15565b61042a8261016001518360200151610c15565b6104349190612997565b602082015261018081015161045f9061045590670de0b6b3a7640000612970565b8760040154610c15565b6104728261018001518360400151610c15565b61047c9190612997565b60408201526101808101516104a79061049d90670de0b6b3a7640000612970565b8760050154610c15565b6104ba8261018001518360600151610c15565b6104c49190612997565b60608201525b805185556020810151600186015560408101516002860155606081015160038601554260048601555b67016345785d8a00008360e00151118015610522575061051e816020015166b1a2bc2ec50000610b1e565b8151105b156105845767016345785d8a0000600160d01b4265ffffffffffff16028117875560e08401516040517f20ae1d4a2e8d297f3820670c20fc79531e31643d4b201892680e7df3c4ab159992610577929161269f565b60405180910390a1610637565b855461a8c0906105a390600160d01b900465ffffffffffff164261295d565b1115610637576105c6838260000151836020015184604001518560600151610d4a565b6101a0820181905260e084015114610637576101a081015165ffffffffffff4216600160d01b026001600160d01b03821617875560e08401516040517f2463616ef8e6f9bddf00e4964b853ad9050f87cd3c73985d2ee6b6c8a83369919261062e929161269f565b60405180910390a15b60c0810151600187015560a0810151600287015560e08101516004870155610100015160059095019490945550505050565b60006106908461068b6301e13380610681874261295d565b61019d908761291c565b610b1e565b90505b9392505050565b600080806106b46301e1338061019d8660e08a013561291c565b90506106c48660a0013582610b1e565b925060006106d6868860a00135610edd565b905060006b033f4a75fb6ff29166751a4b8211156106f657506001610718565b64173eb4c80a82101561070c5750611cdc610718565b61071582610efa565b90505b60006107288a8a60600135610fc4565b905081811115610736578091505b60006107428b84610fda565b905080156107dd576107866107676107628e600001548f600101546110e5565b6110f7565b61068b61077c670de0b6b3a76400008961295d565b8d60600135610b1e565b95506000670de0b6b3a76400006107c46107a089856111a1565b6107bf6107b5670de0b6b3a76400008b61295d565b61068b600a6111b6565b6111ca565b6107ce91906129bf565b90506107db8c85836111da565b505b50505050509550959350505050565b6040516370a0823160e01b815284906000906001600160a01b038316906370a082319061081d9030906004016129d2565b602060405180830381865afa15801561083a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085e91906129e6565b90506108746001600160a01b038316888761137d565b6040516323e30c8b60e01b81527f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9906001600160a01b038916906323e30c8b906108cd9033908b908b906000908c908c906004016129ff565b6020604051808303816000875af11580156108ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091091906129e6565b1461092e5760405163f594248f60e01b815260040160405180910390fd5b6109436001600160a01b0383168830886113e5565b6040516370a0823160e01b815281906001600160a01b038416906370a08231906109719030906004016129d2565b602060405180830381865afa15801561098e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b291906129e6565b146109d0576040516370fc723360e01b815260040160405180910390fd5b856001600160a01b0316876001600160a01b03167f6b15284fe89dbd5c436c2e0b06b1bf72e3a0a8e96d1b4a2abd61dfae2d7849a687604051610a1591815260200190565b60405180910390a350505050505050565b60006101af826110f7565b600080600080600087604001519050600087600001516001600160d01b03169050610a7f82610a7a838b6020015165ffffffffffff168b600001516001600160d01b0316610669565b611423565b610a898383611423565b610a978b6020015184611423565b89608001519550955095509550505093509350935093565b60006101af826000015483600101546110e5565b6000680736ea4425c11ac6318210610af65760405163062bb40d60e31b8152600481018390526024015b60405180910390fd5b6714057b7ef767814f8202610693670de0b6b3a76400006706f05b59d3b2000083010461144f565b6000670de0b6b3a7640000610b34600282612949565b610b3e848661291c565b610b4891906129bf565b6101ac9190612949565b600080610b60858585611495565b905080600003610b78576120008701545b9150610bbb565b6b033f4a75fb6ff29166751a4b8110610b945760009150610bbb565b64173eb4c80a8110610bb257610b7187610bad83610efa565b610fda565b61200087015491505b610bc9826107bf8887610b1e565b610bd3908361295d565b979650505050505050565b600081831015610bee57816101ac565b5090919050565b600081610c03600282612949565b610b3e670de0b6b3a76400008661291c565b6000600160ff1b831480610c2c5750600160ff1b82145b15610c4a57604051630d01a11b60e21b815260040160405180910390fd5b60008060008512610c5b5784610c60565b846000035b915060008412610c705783610c75565b836000035b90506000610c8383836114c2565b90506001600160ff1b03811115610cb05760405163bf79e8d960e01b815260048101829052602401610aed565b600019808713908613808218600114610cc95782610cce565b826000035b98975050505050505050565b600068023f2fa8f6da5b9d3119821215610cf657506000919050565b680736ea4425c11ac6318212610d22576040516399bb754160e01b815260048101839052602401610aed565b6714057b7ef767814f8202610693670de0b6b3a76400006706f05b59d3b20000830105611588565b60008060008760600151600014610d8f57610d6587876110e5565b9150670de0b6b3a7640000610d82670e27c49886e6000084612a5b565b610d8c9190612a8b565b90505b600084600003610da757670de0b6b3a7640000610db1565b610db18686610bf5565b60e08a015194509050670de0b6b3a76400006002633b9aca0082610dd58686612997565b610ddf9190612970565b610de99190612a8b565b610df39190612bee565b610dfd9190612970565b610e078383612970565b610e12906004612a5b565b1215610e3557610e2e8960e00151670f43fc2c04ee0000610b1e565b9350610eb3565b6002633b9aca00670de0b6b3a7640000610e4f8685612997565b610e599190612970565b610e639190612a8b565b610e6d9190612bee565b610e7f90670de0b6b3a7640000612970565b610e898483612970565b610e94906004612a5b565b1315610eb357610eb08960e00151670c7d713b49da0000610b1e565b93505b610ed0673782dace9d9000006107bf66038d7ea4c6800087610bde565b9998505050505050505050565b60006101ac610eec8484610b1e565b670e6ed27d66680000610b1e565b600064173eb4c80a821080610f1a57506b033f4a75fb6ff29166751a4b82115b15610f3857604051635665ba4560e11b815260040160405180910390fd5b6000610f5c610f468461160c565b610f57670df27a2cdf44800061160c565b6116f0565b90506000610f69826117b6565b9050600082128015610f8b57506706f05b59d3b20000610f898383612970565b135b15610fae57610fa6670de0b6b3a7640000820561103d612970565b949350505050565b610fa6670de0b6b3a7640000820561103c612970565b6000610fd08383611824565b5090949350505050565b6000610fe582612bfd565b9150670de0b6b3a7640000612000600080610fff86611914565b905060005b8184106110da5761101584846129bf565b90506120008111611004576000886120010182612001811061103957611039612c16565b01549050878516156110ba5760008983612001811061105a5761105a612c16565b0154905081600003611075576110708782610b1e565b611097565b611097611082838961291c565b826a0c097ce7bc90715b34b9f160241b611933565b6110a190896129bf565b97508294508885036110b45750506110da565b506110cd565b80156110cd576110ca86826119e2565b95505b600185901c945050611004565b505050505092915050565b600081156101af576101ac8383610bf5565b60008061110c83670de0b6b3a76400006111ca565b61111990620f424061291c565b61112d9069d3c21bcecceda100000061295d565b9050670de0b6b3a764000081101561114f5750670de0b6b3a764000092915050565b6000611163826704a03ce68d2155566119f7565b905061118961117a82670214e8348c4f0000610b1e565b68056bc75e2d63100000610bf5565b610fa690670de0b6b3a764000061295d565b50919050565b600081610b48670de0b6b3a76400008561291c565b60006101af670de0b6b3a76400008361291c565b600081831115610bee57816101ac565b6111e382612bfd565b91506000806000806111f486611914565b90505b612000811161137457808616156112e5578686612001811061121b5761121b612c16565b01549250866120010186612001811061123657611236612c16565b01549150811561129857600061124c8684610b1e565b90506112588385610b1e565b6112628286610b1e565b61126c919061295d565b61127690866129bf565b945080886120010188612001811061129057611290612c16565b0155506112d4565b826112a38685610b1e565b6112ad919061295d565b6112b790856129bf565b93508487612001018761200181106112d1576112d1612c16565b01555b6112de818761295d565b955061136c565b60006112f182886129bf565b9050848882612001811061130757611307612c16565b01600082825461131791906129bf565b9250508190559350876120010181612001811061133657611336612c16565b01549250821561136a5761135361134d868661295d565b84610b1e565b61135d8585610b1e565b611367919061295d565b94505b505b60011b6111f7565b50505050505050565b6040516001600160a01b0383166024820152604481018290526113e090849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611a39565b505050565b6040516001600160a01b038085166024830152831660448201526064810182905261141d9085906323b872dd60e01b906084016113a9565b50505050565b6000670de0b6b3a764000060018161143b858761291c565b61144591906129bf565b610b48919061295d565b6000680a688906bd8b000000821061147d57604051634a4f26f160e01b815260048101839052602401610aed565b670de0b6b3a7640000604083901b0461069381611b0b565b600083156114b8576114b36114ad610eec8585610b1e565b85610bf5565b610690565b5060009392505050565b60008080600019848609848602925082811083820303915050670de0b6b3a764000081106115065760405163698d9a0160e11b815260048101829052602401610aed565b600080670de0b6b3a764000086880991506706f05b59d3b1ffff82119050826000036115445780670de0b6b3a76400008504019450505050506101af565b620400008285030493909111909103600160ee1b02919091177faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106690201905092915050565b6000808212156115db5768033dd1780914b97114198212156115ac57506000919050565b6115b882600003611588565b6a0c097ce7bc90715b34b9f160241b816115d4576115d4612933565b0592915050565b680a688906bd8b000000821261147d5760405163e69458f960e01b815260048101839052602401610aed565b919050565b60008082136116315760405163309fa7dd60e11b815260048101839052602401610aed565b6000670de0b6b3a7640000831261164a57506001611663565b6000199050826a0c097ce7bc90715b34b9f160241b0492505b6000611678670de0b6b3a7640000850561219d565b670de0b6b3a764000081029350905083811d670de0b6b3a763ffff1981016116a257505002919050565b6706f05b59d3b200005b60008113156116e757670de0b6b3a7640000828002059150671bc16d674ec8000082126116df579384019360019190911d905b60011d6116ac565b50505002919050565b6000600160ff1b8314806117075750600160ff1b82145b156117255760405163b3c754a360e01b815260040160405180910390fd5b60008060008512611736578461173b565b846000035b91506000841261174b5783611750565b836000035b9050600061176783670de0b6b3a76400008461227b565b90506001600160ff1b0381111561179457604051637cb4bef560e01b815260048101829052602401610aed565b6000198087139086138082186001146117ad5782610cce565b610cce83612c2c565b6000670afdc366fbc00000600160ff1b038213156117ea57604051635399a28560e11b815260048101839052602401610aed565b670de0b6b3a7640000820760008190036118065782915061119b565b8083039150600083131561119b5750670de0b6b3a764000001919050565b60008080611000670de0b6b3a764000082808080805b86156119065761184a878b6129bf565b93508b84612001811061185f5761185f612c16565b015492508b6120010184612001811061187a5761187a612c16565b0154915081600003611895576118908684610b1e565b6118b7565b6118b76118a2838861291c565b846a0c097ce7bc90715b34b9f160241b611933565b6118c190866129bf565b90508a8110156118e057611cdc84116118db578399508094505b6118fa565b81156118f3576118f086836119e2565b95505b8098508597505b600187901c965061183a565b505050505050509250925092565b600081156116075761192b600019831860016129bf565b909116919050565b600080806000198587098587029250828110838203039150508060000361196d5783828161196357611963612933565b0492505050610693565b80841161197957600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000670de0b6b3a7640000610b48838561291c565b600082600003611a1f578115611a0e576000611a18565b670de0b6b3a76400005b90506101af565b6101ac611a34611a2e856122cf565b84612385565b61144f565b6000611a8e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166123919092919063ffffffff16565b8051909150156113e05780806020019051810190611aac9190612c48565b6113e05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610aed565b600160bf1b6001603f1b821615611b2b5768016a09e667f3bcc9090260401c5b6001603e1b821615611b46576801306fe0a31b7152df0260401c5b6001603d1b821615611b61576801172b83c7d517adce0260401c5b6001603c1b821615611b7c5768010b5586cf9890f62a0260401c5b6001603b1b821615611b97576801059b0d31585743ae0260401c5b6001603a1b821615611bb257680102c9a3e778060ee70260401c5b600160391b821615611bcd5768010163da9fb33356d80260401c5b600160381b821615611be857680100b1afa5abcbed610260401c5b600160371b821615611c035768010058c86da1c09ea20260401c5b600160361b821615611c1e576801002c605e2e8cec500260401c5b600160351b821615611c3957680100162f3904051fa10260401c5b600160341b821615611c54576801000b175effdc76ba0260401c5b600160331b821615611c6f57680100058ba01fb9f96d0260401c5b600160321b821615611c8a5768010002c5cc37da94920260401c5b600160311b821615611ca5576801000162e525ee05470260401c5b600160301b821615611cc05768010000b17255775c040260401c5b6001602f1b821615611cdb576801000058b91b5bc9ae0260401c5b6001602e1b821615611cf657680100002c5c89d5ec6d0260401c5b6001602d1b821615611d115768010000162e43f4f8310260401c5b6001602c1b821615611d2c57680100000b1721bcfc9a0260401c5b6001602b1b821615611d475768010000058b90cf1e6e0260401c5b6001602a1b821615611d62576801000002c5c863b73f0260401c5b600160291b821615611d7d57680100000162e430e5a20260401c5b600160281b821615611d98576801000000b1721835510260401c5b600160271b821615611db357680100000058b90c0b490260401c5b600160261b821615611dce5768010000002c5c8601cc0260401c5b600160251b821615611de9576801000000162e42fff00260401c5b600160241b821615611e045768010000000b17217fbb0260401c5b600160231b821615611e1f576801000000058b90bfce0260401c5b600160221b821615611e3a57680100000002c5c85fe30260401c5b600160211b821615611e555768010000000162e42ff10260401c5b600160201b821615611e7057680100000000b17217f80260401c5b6380000000821615611e8b5768010000000058b90bfc0260401c5b6340000000821615611ea6576801000000002c5c85fe0260401c5b6320000000821615611ec157680100000000162e42ff0260401c5b6310000000821615611edc576801000000000b17217f0260401c5b6308000000821615611ef757680100000000058b90c00260401c5b6304000000821615611f125768010000000002c5c8600260401c5b6302000000821615611f2d576801000000000162e4300260401c5b6301000000821615611f485768010000000000b172180260401c5b62800000821615611f62576801000000000058b90c0260401c5b62400000821615611f7c57680100000000002c5c860260401c5b62200000821615611f965768010000000000162e430260401c5b62100000821615611fb057680100000000000b17210260401c5b62080000821615611fca5768010000000000058b910260401c5b62040000821615611fe4576801000000000002c5c80260401c5b62020000821615611ffe57680100000000000162e40260401c5b620100008216156120175761b172600160401b010260401c5b61800082161561202f576158b9600160401b010260401c5b61400082161561204757612c5d600160401b010260401c5b61200082161561205f5761162e600160401b010260401c5b61100082161561207757610b17600160401b010260401c5b61080082161561208f5761058c600160401b010260401c5b6104008216156120a7576102c6600160401b010260401c5b6102008216156120bf57610163600160401b010260401c5b6101008216156120d65760b1600160401b010260401c5b60808216156120ec576059600160401b010260401c5b604082161561210257602c600160401b010260401c5b6020821615612118576016600160401b010260401c5b601082161561212e57600b600160401b010260401c5b6008821615612144576006600160401b010260401c5b600482161561215a576003600160401b010260401c5b6002821615612170576001600160401b010260401c5b6001821615612186576001600160401b010260401c5b670de0b6b3a76400000260409190911c60bf031c90565b6000600160801b82106121bd57608091821c916121ba90826129bf565b90505b600160401b82106121db57604091821c916121d890826129bf565b90505b600160201b82106121f957602091821c916121f690826129bf565b90505b62010000821061221657601091821c9161221390826129bf565b90505b610100821061223257600891821c9161222f90826129bf565b90505b6010821061224d57600491821c9161224a90826129bf565b90505b6004821061226857600291821c9161226590826129bf565b90505b60028210611607576101af6001826129bf565b60008080600019858709858702925082811083820303915050806000036122ab5783828161196357611963612933565b838110611979578084604051631dcf306360e21b8152600401610aed92919061269f565b6000670de0b6b3a76400008210156122fd57604051633621413760e21b815260048101839052602401610aed565b6000612312670de0b6b3a7640000840461219d565b670de0b6b3a764000081029250905082811c670de0b6b3a763ffff19810161233b575050919050565b6706f05b59d3b200005b801561237d57670de0b6b3a7640000828002049150671bc16d674ec800008210612375579283019260019190911c905b60011c612345565b505050919050565b60006101ac83836114c2565b6060610690848460008585600080866001600160a01b031685876040516123b89190612c89565b60006040518083038185875af1925050503d80600081146123f5576040519150601f19603f3d011682016040523d82523d6000602084013e6123fa565b606091505b5091509150610bd3878383876060831561247557825160000361246e576001600160a01b0385163b61246e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610aed565b5081610fa6565b610fa6838381511561248a5781518083602001fd5b8060405162461bcd60e51b8152600401610aed9190612ca5565b600080604083850312156124b757600080fd5b50508035926020909101359150565b60405161012081016001600160401b03811182821017156124f757634e487b7160e01b600052604160045260246000fd5b60405290565b604080519081016001600160401b03811182821017156124f757634e487b7160e01b600052604160045260246000fd5b803560ff8116811461160757600080fd5b801515811461254c57600080fd5b50565b80356116078161253e565b60008060008060008587036101a081121561257457600080fd5b86359550602087013594506040870135935061012080605f198301121561259a57600080fd5b6125a26124c6565b91506125b06060890161252d565b82526080880135602083015260a0880135604083015260c0880135606083015260e088013560808301526101008089013560a08401526125f1828a0161254f565b60c084015261014089013560e0840152610160890135908301525094979396509194610180013592915050565b60008060006060848603121561263357600080fd5b505081359360208301359350604090920135919050565b60008060008060008587036101a081121561266457600080fd5b8635955060208701359450610120603f198201121561268257600080fd5b509396929550505060408301926101608101359250610180013590565b918252602082015260400190565b6001600160a01b038116811461254c57600080fd5b6000806000806000608086880312156126da57600080fd5b85356126e5816126ad565b945060208601356126f5816126ad565b93506040860135925060608601356001600160401b038082111561271857600080fd5b818801915088601f83011261272c57600080fd5b81358181111561273b57600080fd5b89602082850101111561274d57600080fd5b9699959850939650602001949392505050565b60006020828403121561277257600080fd5b5035919050565b80356001600160d01b038116811461160757600080fd5b803565ffffffffffff8116811461160757600080fd5b600060e082840312156127b857600080fd5b60405160e081016001600160401b03811182821017156127e857634e487b7160e01b600052604160045260246000fd5b6040529050806127f783612779565b815261280560208401612790565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c08201525092915050565b600080600083850361018081121561285a57600080fd5b606081121561286857600080fd5b604051606081016001600160401b038111828210171561289857634e487b7160e01b600052604160045260246000fd5b604090815286358252602080880135908301528681013582820152909450605f19820112156128c657600080fd5b506128cf6124fd565b6128db60608601612779565b81526128e960808601612790565b602082015291506128fd8560a086016127a6565b90509250925092565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176101af576101af612906565b634e487b7160e01b600052601260045260246000fd5b60008261295857612958612933565b500490565b818103818111156101af576101af612906565b818103600083128015838313168383128216171561299057612990612906565b5092915050565b80820182811260008312801582168215821617156129b7576129b7612906565b505092915050565b808201808211156101af576101af612906565b6001600160a01b0391909116815260200190565b6000602082840312156129f857600080fd5b5051919050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b80820260008212600160ff1b84141615612a7757612a77612906565b81810583148215176101af576101af612906565b600082612a9a57612a9a612933565b600160ff1b821460001984141615612ab457612ab4612906565b500590565b80825b6001808611612acb5750612afe565b6001600160ff1b03829004821115612ae557612ae5612906565b80861615612af257918102915b9490941c938002612abc565b935093915050565b6000828015612b1c5760018114612b2657612b2f565b60019150506101af565b829150506101af565b5081612b3d575060006101af565b50600160008213808214612b56578015612b7557612b8f565b6001600160ff1b03839004831115612b7057612b70612906565b612b8f565b6001600160ff1b03839005831215612b8f57612b8f612906565b5080831615612b9b5750805b612bab8360011c83840283612ab9565b600082136001600160ff1b0382900483111615612bca57612bca612906565b60008212600160ff1b82900583121615612be657612be6612906565b029392505050565b60006101ac60ff841683612b06565b600060018201612c0f57612c0f612906565b5060010190565b634e487b7160e01b600052603260045260246000fd5b6000600160ff1b8201612c4157612c41612906565b5060000390565b600060208284031215612c5a57600080fd5b81516106938161253e565b60005b83811015612c80578181015183820152602001612c68565b50506000910152565b60008251612c9b818460208701612c65565b9190910192915050565b6020815260008251806020840152612cc4816040850160208701612c65565b601f01601f1916919091016040019291505056fea2646970667358221220355b992d4aaf3160c026285d382b9ee30781a9e373d5f9e4fc0ca9be8f602cf864736f6c63430008120033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.