Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
SpotEngine
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 40 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./common/Constants.sol"; import "./common/Errors.sol"; import "./interfaces/engine/ISpotEngine.sol"; import "./interfaces/clearinghouse/IClearinghouse.sol"; import "./libraries/MathHelper.sol"; import "./libraries/MathSD21x18.sol"; import "./libraries/RiskHelper.sol"; import "./BaseEngine.sol"; import "./SpotEngineState.sol"; import "./SpotEngineLP.sol"; contract SpotEngine is SpotEngineLP { using MathSD21x18 for int128; function initialize( address _clearinghouse, address _offchainExchange, address _quote, address _endpoint, address _admin ) external { _initialize(_clearinghouse, _offchainExchange, _endpoint, _admin); configs[QUOTE_PRODUCT_ID] = Config({ token: _quote, interestInflectionUtilX18: 8e17, // .8 interestFloorX18: 1e16, // .01 interestSmallCapX18: 4e16, // .04 interestLargeCapX18: ONE // 1 }); _risk().value[QUOTE_PRODUCT_ID] = RiskHelper.RiskStore({ longWeightInitial: 1e9, shortWeightInitial: 1e9, longWeightMaintenance: 1e9, shortWeightMaintenance: 1e9, priceX18: ONE }); states[QUOTE_PRODUCT_ID] = State({ cumulativeDepositsMultiplierX18: ONE, cumulativeBorrowsMultiplierX18: ONE, totalDepositsNormalized: 0, totalBorrowsNormalized: 0 }); productIds.push(QUOTE_PRODUCT_ID); emit AddProduct(QUOTE_PRODUCT_ID); } /** * View */ function getEngineType() external pure returns (EngineType) { return EngineType.SPOT; } function getConfig(uint32 productId) external view returns (Config memory) { return configs[productId]; } function getWithdrawFee(uint32 productId) external pure returns (int128) { // TODO: use the map the store withdraw fees // return withdrawFees[productId]; if ( productId == QUOTE_PRODUCT_ID || productId == 5 || productId == 31 || productId == 41 || productId == 109 ) { // USDC, ARB, USDT, VRTX, MNT return 1e18; } else if (productId == 1) { // BTC return 4e13; } else if ( productId == 3 || productId == 91 || productId == 93 || productId == 111 ) { // ETH (arbi), ETH (blast), ETH (mantle), wETH return 6e14; } return 0; } /** * Actions */ /// @notice adds a new product with default parameters function addProduct( uint32 productId, uint32 quoteId, address book, int128 sizeIncrement, int128 minSize, int128 lpSpreadX18, Config calldata config, RiskHelper.RiskStore calldata riskStore ) public onlyOwner { require(productId != QUOTE_PRODUCT_ID); _addProductForId( productId, quoteId, book, sizeIncrement, minSize, lpSpreadX18, riskStore ); configs[productId] = config; states[productId] = State({ cumulativeDepositsMultiplierX18: ONE, cumulativeBorrowsMultiplierX18: ONE, totalDepositsNormalized: 0, totalBorrowsNormalized: 0 }); lpStates[productId] = LpState({ supply: 0, quote: Balance({amount: 0, lastCumulativeMultiplierX18: ONE}), base: Balance({amount: 0, lastCumulativeMultiplierX18: ONE}) }); } function updateProduct(bytes calldata rawTxn) external onlyEndpoint { UpdateProductTx memory txn = abi.decode(rawTxn, (UpdateProductTx)); RiskHelper.RiskStore memory riskStore = txn.riskStore; if (txn.productId != QUOTE_PRODUCT_ID) { require( riskStore.longWeightInitial <= riskStore.longWeightMaintenance && riskStore.shortWeightInitial >= riskStore.shortWeightMaintenance && configs[txn.productId].token == txn.config.token, ERR_BAD_PRODUCT_CONFIG ); RiskHelper.RiskStore memory r = _risk().value[txn.productId]; r.longWeightInitial = riskStore.longWeightInitial; r.shortWeightInitial = riskStore.shortWeightInitial; r.longWeightMaintenance = riskStore.longWeightMaintenance; r.shortWeightMaintenance = riskStore.shortWeightMaintenance; _risk().value[txn.productId] = r; _exchange().updateMarket( txn.productId, type(uint32).max, address(0), txn.sizeIncrement, txn.minSize, txn.lpSpreadX18 ); } configs[txn.productId] = txn.config; } function updateQuoteFromInsurance(bytes32 subaccount, int128 insurance) external returns (int128) { _assertInternal(); State memory state = states[QUOTE_PRODUCT_ID]; BalanceNormalized memory balanceNormalized = balances[QUOTE_PRODUCT_ID][ subaccount ].balance; int128 balanceAmount = balanceNormalizedToBalance( state, balanceNormalized ).amount; if (balanceAmount < 0) { int128 topUpAmount = MathHelper.max( MathHelper.min(insurance, -balanceAmount), 0 ); insurance -= topUpAmount; _updateBalanceNormalized(state, balanceNormalized, topUpAmount); } states[QUOTE_PRODUCT_ID] = state; balances[QUOTE_PRODUCT_ID][subaccount].balance = balanceNormalized; return insurance; } function updateBalance( uint32 productId, bytes32 subaccount, int128 amountDelta, int128 quoteDelta ) external { require(productId != QUOTE_PRODUCT_ID, ERR_INVALID_PRODUCT); _assertInternal(); State memory state = states[productId]; State memory quoteState = states[QUOTE_PRODUCT_ID]; BalanceNormalized memory balance = balances[productId][subaccount] .balance; BalanceNormalized memory quoteBalance = balances[QUOTE_PRODUCT_ID][ subaccount ].balance; _updateBalanceNormalized(state, balance, amountDelta); _updateBalanceNormalized(quoteState, quoteBalance, quoteDelta); balances[productId][subaccount].balance = balance; balances[QUOTE_PRODUCT_ID][subaccount].balance = quoteBalance; states[productId] = state; states[QUOTE_PRODUCT_ID] = quoteState; _balanceUpdate(productId, subaccount); _balanceUpdate(QUOTE_PRODUCT_ID, subaccount); } function updateBalance( uint32 productId, bytes32 subaccount, int128 amountDelta ) external { _assertInternal(); State memory state = states[productId]; BalanceNormalized memory balance = balances[productId][subaccount] .balance; _updateBalanceNormalized(state, balance, amountDelta); balances[productId][subaccount].balance = balance; states[productId] = state; _balanceUpdate(productId, subaccount); } // only check on withdraw -- ensure that users can't withdraw // funds that are in the Vertex contract but not officially // 'deposited' into the Vertex system and counted in balances // (i.e. if a user transfers tokens to the clearinghouse // without going through the standard deposit) function assertUtilization(uint32 productId) external view { (State memory _state, ) = getStateAndBalance(productId, X_ACCOUNT); int128 totalDeposits = _state.totalDepositsNormalized.mul( _state.cumulativeDepositsMultiplierX18 ); int128 totalBorrows = _state.totalBorrowsNormalized.mul( _state.cumulativeBorrowsMultiplierX18 ); require(totalDeposits >= totalBorrows, ERR_MAX_UTILIZATION); } function socializeSubaccount(bytes32 subaccount) external { require(msg.sender == address(_clearinghouse), ERR_UNAUTHORIZED); uint32[] memory _productIds = getProductIds(); for (uint128 i = 0; i < _productIds.length; ++i) { uint32 productId = _productIds[i]; State memory state = states[productId]; Balance memory balance = balanceNormalizedToBalance( state, balances[productId][subaccount].balance ); if (balance.amount < 0) { int128 totalDeposited = state.totalDepositsNormalized.mul( state.cumulativeDepositsMultiplierX18 ); state.cumulativeDepositsMultiplierX18 = (totalDeposited + balance.amount).div(state.totalDepositsNormalized); require(state.cumulativeDepositsMultiplierX18 > 0); state.totalBorrowsNormalized += balance.amount.div( state.cumulativeBorrowsMultiplierX18 ); balances[productId][subaccount].balance.amountNormalized = 0; if (productId == QUOTE_PRODUCT_ID) { for (uint32 j = 0; j < _productIds.length; ++j) { uint32 baseProductId = _productIds[j]; if (baseProductId == QUOTE_PRODUCT_ID) { continue; } LpState memory lpState = lpStates[baseProductId]; _updateBalanceWithoutDelta(state, lpState.quote); lpStates[baseProductId] = lpState; _productUpdate(baseProductId); } } else { LpState memory lpState = lpStates[productId]; _updateBalanceWithoutDelta(state, lpState.base); lpStates[productId] = lpState; } states[productId] = state; _balanceUpdate(productId, subaccount); } } } function manualAssert( int128[] calldata totalDeposits, int128[] calldata totalBorrows ) external view { for (uint128 i = 0; i < totalDeposits.length; ++i) { uint32 productId = productIds[i]; State memory state = states[productId]; require( state.totalDepositsNormalized.mul( state.cumulativeDepositsMultiplierX18 ) == totalDeposits[i], ERR_DSYNC ); require( state.totalBorrowsNormalized.mul( state.cumulativeBorrowsMultiplierX18 ) == totalBorrows[i], ERR_DSYNC ); } } function getToken(uint32 productId) external view returns (address) { return address(configs[productId].token); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; /// @dev Each clearinghouse has a unique quote product uint32 constant QUOTE_PRODUCT_ID = 0; /// @dev Fees account bytes32 constant FEES_ACCOUNT = bytes32(0); bytes32 constant X_ACCOUNT = 0x0000000000000000000000000000000000000000000000000000000000000001; string constant DEFAULT_REFERRAL_CODE = "-1"; uint128 constant MINIMUM_LIQUIDITY = 10**3; int128 constant ONE = 10**18; uint8 constant MAX_DECIMALS = 18; int128 constant TAKER_SEQUENCER_FEE = 0; // $0.00 int128 constant SLOW_MODE_FEE = 1000000; // $1 int128 constant FAST_WITHDRAWAL_FEE_RATE = 1_000_000_000_000_000; // 0.1% int128 constant LIQUIDATION_FEE = 1e18; // $1 int128 constant HEALTHCHECK_FEE = 1e18; // $1 uint128 constant INT128_MAX = uint128(type(int128).max); uint64 constant SECONDS_PER_DAY = 3600 * 24; uint32 constant VRTX_PRODUCT_ID = 41; int128 constant LIQUIDATION_FEE_FRACTION = 500_000_000_000_000_000; // 50% int128 constant INTEREST_FEE_FRACTION = 200_000_000_000_000_000; // 20% int256 constant MIN_DEPOSIT_AMOUNT = 5 * ONE; uint32 constant MAX_ISOLATED_SUBACCOUNTS_PER_ADDRESS = 10;
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; // Trying to take an action on vertex when string constant ERR_REQUIRES_DEPOSIT = "RS"; // ERC20 Transfer failed string constant ERR_TRANSFER_FAILED = "TF"; // Unauthorized string constant ERR_UNAUTHORIZED = "U"; // Invalid product string constant ERR_INVALID_PRODUCT = "IP"; // Subaccount health too low string constant ERR_SUBACCT_HEALTH = "SH"; // Not liquidatable string constant ERR_NOT_LIQUIDATABLE = "NL"; // Liquidator health too low string constant ERR_NOT_LIQUIDATABLE_INITIAL = "NLI"; // Liquidatee has positive initial health string constant ERR_LIQUIDATED_TOO_MUCH = "LTM"; // Trying to liquidate quote, or string constant ERR_INVALID_LIQUIDATION_PARAMS = "NILP"; // Trying to liquidate perp but the amount is not divisible by sizeIncrement string constant ERR_INVALID_LIQUIDATION_AMOUNT = "NILA"; // Tried to liquidate too little, too much or signs are different string constant ERR_NOT_LIQUIDATABLE_AMT = "NLA"; // Tried to liquidate liabilities before perps string constant ERR_NOT_LIQUIDATABLE_LIABILITIES = "NLL"; // Tried to finalize subaccount that cannot be finalized string constant ERR_NOT_FINALIZABLE_SUBACCOUNT = "NFS"; // Not enough quote to settle string constant ERR_CANNOT_SETTLE = "CS"; // Not enough insurance to settle string constant ERR_NO_INSURANCE = "NI"; // Above reserve ratio string constant ERR_RESERVE_RATIO = "RR"; // Invalid socialize amount string constant ERR_INVALID_SOCIALIZE_AMT = "ISA"; // Socializing product with no open interest string constant ERR_NO_OPEN_INTEREST = "NOI"; // FOK not filled, this isn't rly an error so this is jank string constant ERR_FOK_NOT_FILLED = "ENF"; // bad product config via weights string constant ERR_BAD_PRODUCT_CONFIG = "BPC"; // subacct name too long string constant ERR_LONG_NAME = "LN"; // already registered in health group string constant ERR_ALREADY_REGISTERED = "AR"; // invalid health group provided string constant ERR_INVALID_HEALTH_GROUP = "IHG"; string constant ERR_GETTING_ZERO_HEALTH_GROUP = "GZHG"; // trying to burn more LP than owned string constant ERR_INSUFFICIENT_LP = "ILP"; // taker order subaccount fails risk or is invalid string constant ERR_INVALID_TAKER = "IT"; // maker order subaccount fails risk or is invalid string constant ERR_INVALID_MAKER = "IM"; string constant ERR_INVALID_SIGNATURE = "IS"; string constant ERR_ORDERS_CANNOT_BE_MATCHED = "OCBM"; string constant ERR_INVALID_LP_AMOUNT = "ILA"; string constant ERR_SLIPPAGE_TOO_HIGH = "STH"; string constant ERR_SUBACCOUNT_NOT_FOUND = "SNF"; string constant ERR_INVALID_PRICE = "IPR"; string constant ERR_INVALID_TIME = "ITI"; // states on node and engine are not same string constant ERR_DSYNC = "DSYNC"; string constant ERR_INVALID_SWAP_PARAMS = "ISP"; string constant ERR_CONVERSION_OVERFLOW = "CO"; string constant ERR_ONLY_CLEARINGHOUSE_CAN_SET_BOOK = "OCCSB"; // we match on containing these strings in sequencer string constant ERR_INVALID_SUBMISSION_INDEX = "IX"; string constant ERR_NO_SLOW_MODE_TXS_REMAINING = "no slow mode transactions remaining"; string constant ERR_INVALID_COUNT = "IC"; string constant ERR_SLOW_TX_TOO_RECENT = "STTR"; string constant ERR_WALLET_NOT_TRANSFERABLE = "WNT"; string constant ERR_WALLET_SANCTIONED = "WS"; string constant ERR_SLOW_MODE_WRONG_SENDER = "SMWS"; string constant ERR_WRONG_NONCE = "WN"; // initially wanted to call this // ERR_FULL_UTILIZATION but the shortened // error string may make people mad on the frontend string constant ERR_MAX_UTILIZATION = "MU"; string constant ERR_INVALID_RISK_GROUP = "IRG"; string constant ERR_VERIFY_SCHNORR = "VSR"; string constant ERR_DEPOSIT_TOO_SMALL = "DTS"; string constant ERR_CODE_NOT_MATCH = "CNM";
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./IProductEngine.sol"; import "../../libraries/RiskHelper.sol"; interface ISpotEngine is IProductEngine { event InterestPayment( uint32 productId, uint128 dt, int128 depositRateMultiplierX18, int128 borrowRateMultiplierX18, int128 feeAmount ); struct Config { address token; int128 interestInflectionUtilX18; int128 interestFloorX18; int128 interestSmallCapX18; int128 interestLargeCapX18; } struct State { int128 cumulativeDepositsMultiplierX18; int128 cumulativeBorrowsMultiplierX18; int128 totalDepositsNormalized; int128 totalBorrowsNormalized; } struct Balance { int128 amount; int128 lastCumulativeMultiplierX18; } struct BalanceNormalized { int128 amountNormalized; } struct LpState { int128 supply; Balance quote; Balance base; } struct LpBalance { int128 amount; } struct Balances { BalanceNormalized balance; LpBalance lpBalance; } struct UpdateProductTx { uint32 productId; int128 sizeIncrement; int128 minSize; int128 lpSpreadX18; Config config; RiskHelper.RiskStore riskStore; } function getStateAndBalance(uint32 productId, bytes32 subaccount) external view returns (State memory, Balance memory); function getBalance(uint32 productId, bytes32 subaccount) external view returns (Balance memory); function getStatesAndBalances(uint32 productId, bytes32 subaccount) external view returns ( LpState memory, LpBalance memory, State memory, Balance memory ); function getConfig(uint32 productId) external view returns (Config memory); function getWithdrawFee(uint32 productId) external view returns (int128); function getToken(uint32 productId) external view returns (address); function updateBalance( uint32 productId, bytes32 subaccount, int128 amountDelta ) external; function updateBalance( uint32 productId, bytes32 subaccount, int128 amountDelta, int128 quoteDelta ) external; function updateQuoteFromInsurance(bytes32 subaccount, int128 insurance) external returns (int128); function updateStates(uint128 dt) external; function updateMinDepositRate(uint32 productId, int128 minDepositRateX18) external; function manualAssert( int128[] calldata totalDeposits, int128[] calldata totalBorrows ) external view; function socializeSubaccount(bytes32 subaccount) external; function assertUtilization(uint32 productId) external view; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./IClearinghouseEventEmitter.sol"; import "../engine/IProductEngine.sol"; import "../IEndpoint.sol"; import "../IEndpointGated.sol"; import "../../libraries/RiskHelper.sol"; interface IClearinghouse is IClearinghouseEventEmitter, IEndpointGated { function addEngine( address engine, address offchainExchange, IProductEngine.EngineType engineType ) external; function registerProduct(uint32 productId) external; function transferQuote(IEndpoint.TransferQuote calldata tx) external; function depositCollateral(IEndpoint.DepositCollateral calldata tx) external; function withdrawCollateral( bytes32 sender, uint32 productId, uint128 amount, address sendTo, uint64 idx ) external; function mintLp(IEndpoint.MintLp calldata tx) external; function burnLp(IEndpoint.BurnLp calldata tx) external; function liquidateSubaccount(IEndpoint.LiquidateSubaccount calldata tx) external; function depositInsurance(bytes calldata transaction) external; function withdrawInsurance(bytes calldata transaction, uint64 idx) external; function settlePnl(bytes calldata transaction) external; function claimSequencerFees( IEndpoint.ClaimSequencerFees calldata tx, int128[] calldata fees ) external; /// @notice Retrieve quote ERC20 address function getQuote() external view returns (address); /// @notice Returns the registered engine address by type function getEngineByType(IProductEngine.EngineType engineType) external view returns (address); /// @notice Returns the engine associated with a product ID function getEngineByProduct(uint32 productId) external view returns (address); /// @notice Returns health for the subaccount across all engines function getHealth(bytes32 subaccount, IProductEngine.HealthType healthType) external view returns (int128); /// @notice Returns the amount of insurance remaining in this clearinghouse function getInsurance() external view returns (int128); function getSpreads() external view returns (uint256); function upgradeClearinghouseLiq(address _clearinghouseLiq) external; function getClearinghouseLiq() external view returns (address); function burnLpAndTransfer(IEndpoint.BurnLpAndTransfer calldata txn) external; function requireMinDeposit(uint32 productId, uint128 amount) external; function assertCode(bytes calldata tx) external; function manualAssert(bytes calldata tx) external; function getWithdrawPool() external view returns (address); function getSlowModeFee() external view returns (uint256); function setWithdrawPool(address _withdrawPool) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./MathSD21x18.sol"; /// @title MathHelper /// @dev Provides basic math functions library MathHelper { using MathSD21x18 for int128; /// @notice Returns market id for two given product ids function max(int128 a, int128 b) internal pure returns (int128) { return a > b ? a : b; } function min(int128 a, int128 b) internal pure returns (int128) { return a < b ? a : b; } function abs(int128 val) internal pure returns (int128) { return val < 0 ? -val : val; } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(int128 y) internal pure returns (int128 z) { require(y >= 0, "ds-math-sqrt-non-positive"); if (y > 3) { z = y; int128 x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } function sqrt256(int256 y) internal pure returns (int256 z) { require(y >= 0, "ds-math-sqrt-non-positive"); if (y > 3) { z = y; int256 x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } function int2str(int128 value) internal pure returns (string memory) { if (value == 0) { return "0"; } bool negative = value < 0; uint128 absval = uint128(negative ? -value : value); string memory out = uint2str(absval); if (negative) { out = string.concat("-", out); } return out; } function uint2str(uint128 value) internal pure returns (string memory) { if (value == 0) { return "0"; } uint128 temp = value; uint128 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint128(value % 10))); value /= 10; } return string(buffer); } // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0/contracts/math/SignedSafeMath.sol#L86 function add(int128 x, int128 y) internal pure returns (int128) { int128 z = x + y; require((y >= 0 && z >= x) || (y < 0 && z < x), "ds-math-add-overflow"); return z; } // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0/contracts/math/SignedSafeMath.sol#L69 function sub(int128 x, int128 y) internal pure returns (int128) { int128 z = x - y; require( (y >= 0 && z <= x) || (y < 0 && z > x), "ds-math-sub-underflow" ); return z; } function mul(int128 x, int128 y) internal pure returns (int128 z) { require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); } function floor(int128 x, int128 y) internal pure returns (int128 z) { require(y > 0, "ds-math-floor-neg-mod"); int128 r = x % y; if (r == 0) { z = x; } else { z = (x >= 0 ? x - r : x - r - y); } } function ceil(int128 x, int128 y) internal pure returns (int128 z) { require(y > 0, "ds-math-ceil-neg-mod"); int128 r = x % y; if (r == 0) { z = x; } else { z = (x >= 0 ? x + y - r : x - r); } } // we don't need to floor base with sizeIncrement in this function // because this function is only used by `view` functions, which means // the returned values will not be written into storage. function ammEquilibrium( int128 base, int128 quote, int128 priceX18 ) internal pure returns (int128, int128) { if (base == 0 || quote == 0) { return (0, 0); } int256 k = int256(base) * quote; // base * price * base == k // base = sqrt(k / price); base = int128(MathHelper.sqrt256((k * 1e18) / priceX18)); quote = (base == 0) ? int128(0) : int128(k / base); return (base, quote); } function isSwapValid( int128 baseDelta, int128 quoteDelta, int128 base, int128 quote ) internal pure returns (bool) { if ( base == 0 || quote == 0 || base + baseDelta <= 0 || quote + quoteDelta <= 0 ) { return false; } int256 kPrev = int256(base) * quote; int256 kNew = int256(base + baseDelta) * (quote + quoteDelta); return kNew > kPrev; } function swap( int128 amountSwap, int128 base, int128 quote, int128 priceX18, int128 sizeIncrement, int128 lpSpreadX18 ) internal pure returns (int128, int128) { // (amountSwap % sizeIncrement) is guaranteed to be 0 if (base == 0 || quote == 0) { return (0, 0); } int128 currentPriceX18 = quote.div(base); int128 keepRateX18 = 1e18 - lpSpreadX18; // selling if (amountSwap > 0) { priceX18 = priceX18.div(keepRateX18); if (priceX18 >= currentPriceX18) { return (0, 0); } } else { priceX18 = priceX18.mul(keepRateX18); if (priceX18 <= currentPriceX18) { return (0, 0); } } int256 k = int256(base) * quote; int128 baseAtPrice = int128( (MathHelper.sqrt256(k) * 1e9) / MathHelper.sqrt(priceX18) ); // base -> base + amountSwap int128 baseSwapped; if ( (amountSwap > 0 && base + amountSwap > baseAtPrice) || (amountSwap < 0 && base + amountSwap < baseAtPrice) ) { // we hit price limits before we exhaust amountSwap if (baseAtPrice >= base) { baseSwapped = MathHelper.floor( baseAtPrice - base, sizeIncrement ); } else { baseSwapped = MathHelper.ceil( baseAtPrice - base, sizeIncrement ); } } else { // just swap it all // amountSwap is already guaranteed to adhere to sizeIncrement baseSwapped = amountSwap; } int128 quoteSwapped = int128(k / (base + baseSwapped) - quote); if (amountSwap > 0) { quoteSwapped = quoteSwapped.mul(keepRateX18); } else { quoteSwapped = quoteSwapped.div(keepRateX18); } return (baseSwapped, quoteSwapped); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "prb-math/contracts/PRBMathSD59x18.sol"; library MathSD21x18 { using PRBMathSD59x18 for int256; int128 private constant ONE_X18 = 1000000000000000000; int128 private constant MIN_X18 = -0x80000000000000000000000000000000; int128 private constant MAX_X18 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; string private constant ERR_OVERFLOW = "OF"; string private constant ERR_DIV_BY_ZERO = "DBZ"; function fromInt(int128 x) internal pure returns (int128) { unchecked { int256 result = int256(x) * ONE_X18; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function mulDiv( int128 x, int128 y, int128 z ) internal pure returns (int128) { unchecked { require(z != 0, ERR_DIV_BY_ZERO); int256 result = (int256(x) * y) / z; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function toInt(int128 x) internal pure returns (int128) { unchecked { return int128(x / ONE_X18); } } function add(int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) + y; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function sub(int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) - y; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function mul(int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = (int256(x) * y) / ONE_X18; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function div(int128 x, int128 y) internal pure returns (int128) { unchecked { require(y != 0, ERR_DIV_BY_ZERO); int256 result = (int256(x) * ONE_X18) / y; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function abs(int128 x) internal pure returns (int128) { unchecked { require(x != MIN_X18, ERR_OVERFLOW); return x < 0 ? -x : x; } } function sqrt(int128 x) internal pure returns (int128) { unchecked { int256 result = int256(x).sqrt(); require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } // note that y is not X18 function pow(int128 x, int128 y) internal pure returns (int128) { unchecked { require(y >= 0, ERR_OVERFLOW); int128 result = ONE_X18; for (int128 i = 1; i <= y; i *= 2) { if (i & y != 0) { result = mul(result, x); } x = mul(x, x); } return result; } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./MathSD21x18.sol"; import "../interfaces/engine/IProductEngine.sol"; import "../common/Constants.sol"; import "../common/Errors.sol"; import "./MathHelper.sol"; /// @title RiskHelper /// @dev Provides basic math functions library RiskHelper { using MathSD21x18 for int128; struct RiskStore { // these weights are all // between 0 and 2 // these integers are the real // weights times 1e9 int32 longWeightInitial; int32 shortWeightInitial; int32 longWeightMaintenance; int32 shortWeightMaintenance; int128 priceX18; } struct Risk { int128 longWeightInitialX18; int128 shortWeightInitialX18; int128 longWeightMaintenanceX18; int128 shortWeightMaintenanceX18; int128 priceX18; } function _getSpreadHealthRebateAmount( Risk memory perpRisk, int128 basisAmount, int128 priceSumX18, IProductEngine.HealthType healthType ) internal pure returns (int128) { // 5x more leverage than the standard perp // by refunding 4/5 of the health penalty int128 rebateRateX18 = ((ONE - _getWeightX18(perpRisk, 1, healthType)) * 4) / 5; return rebateRateX18.mul(priceSumX18).mul(basisAmount); } function _getLpRawValue( int128 baseAmount, int128 quoteAmount, int128 priceX18 ) internal pure returns (int128) { // naive way: value an LP token by value of the raw components 2 * arithmetic mean of base value and quote value // price manipulation proof way: use the geometric mean return 2 * int128( MathHelper.sqrt256( int256(baseAmount.mul(priceX18)) * quoteAmount ) ); } function _getWeightX18( Risk memory risk, int128 amount, IProductEngine.HealthType healthType ) internal pure returns (int128) { // (1 + imf * sqrt(amount)) if (healthType == IProductEngine.HealthType.PNL) { return ONE; } int128 weight; if (amount >= 0) { weight = healthType == IProductEngine.HealthType.INITIAL ? risk.longWeightInitialX18 : risk.longWeightMaintenanceX18; } else { weight = healthType == IProductEngine.HealthType.INITIAL ? risk.shortWeightInitialX18 : risk.shortWeightMaintenanceX18; } return weight; } function isIsolatedSubaccount(bytes32 subaccount) internal pure returns (bool) { return uint256(subaccount) & 0xFFFFFF == 6910831; } function getIsolatedProductId(bytes32 subaccount) internal pure returns (uint32) { if (!isIsolatedSubaccount(subaccount)) { return 0; } return uint32((uint256(subaccount) >> 32) & 0xFFFF); } function getIsolatedId(bytes32 subaccount) internal pure returns (uint8) { if (!isIsolatedSubaccount(subaccount)) { return 0; } return uint8((uint256(subaccount) >> 24) & 0xFF); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "hardhat/console.sol"; import "./common/Constants.sol"; import "./common/Errors.sol"; import "./libraries/MathHelper.sol"; import "./libraries/MathSD21x18.sol"; import "./interfaces/clearinghouse/IClearinghouse.sol"; import "./interfaces/engine/IProductEngine.sol"; import "./interfaces/IOffchainExchange.sol"; import "./interfaces/IEndpoint.sol"; import "./EndpointGated.sol"; import "./libraries/Logger.sol"; abstract contract BaseEngine is IProductEngine, EndpointGated { using MathSD21x18 for int128; IClearinghouse internal _clearinghouse; address internal _fees; // deprecated uint32[] internal productIds; mapping(uint32 => address) internal markets; // deprecated // Whether an address can apply deltas - all orderbooks and clearinghouse is whitelisted mapping(address => bool) internal canApplyDeltas; bytes32 internal constant RISK_STORAGE = keccak256("vertex.protocol.risk"); event BalanceUpdate(uint32 productId, bytes32 subaccount); event ProductUpdate(uint32 productId); function _productUpdate(uint32 productId) internal virtual {} struct Uint256Slot { uint256 value; } struct RiskStoreMappingSlot { mapping(uint32 => RiskHelper.RiskStore) value; } function _risk() internal pure returns (RiskStoreMappingSlot storage r) { bytes32 slot = RISK_STORAGE; assembly { r.slot := slot } } function _risk(uint32 productId, RiskStoreMappingSlot storage rmap) internal view returns (RiskHelper.Risk memory r) { RiskHelper.RiskStore memory s = rmap.value[productId]; r.longWeightInitialX18 = int128(s.longWeightInitial) * 1e9; r.shortWeightInitialX18 = int128(s.shortWeightInitial) * 1e9; r.longWeightMaintenanceX18 = int128(s.longWeightMaintenance) * 1e9; r.shortWeightMaintenanceX18 = int128(s.shortWeightMaintenance) * 1e9; r.priceX18 = s.priceX18; } function _risk(uint32 productId) internal view returns (RiskHelper.Risk memory) { return _risk(productId, _risk()); } function getRisk(uint32 productId) external view returns (RiskHelper.Risk memory) { return _risk(productId); } function _getInLpBalance(uint32 productId, bytes32 subaccount) internal view virtual returns ( // baseAmount, quoteAmount, quoteDeltaAmount (funding) int128, int128, int128 ); function _getBalance(uint32 productId, bytes32 subaccount) internal view virtual returns (int128, int128); function getHealthContribution( bytes32 subaccount, IProductEngine.HealthType healthType ) public view returns (int128 health) { uint32[] memory _productIds = getProductIds(); RiskStoreMappingSlot storage r = _risk(); for (uint32 i = 0; i < _productIds.length; i++) { uint32 productId = _productIds[i]; RiskHelper.Risk memory risk = _risk(productId, r); { (int128 amount, int128 quoteAmount) = _getBalance( productId, subaccount ); int128 weight = RiskHelper._getWeightX18( risk, amount, healthType ); health += quoteAmount; if (amount != 0) { // anything with a short weight of 2 is a spot that // should not count towards health and exists out of the risk system // if we're getting a weight of 2 it means this is attempting to short // the spot, so we should error out if (weight == 2 * ONE) { return type(int128).min; } health += amount.mul(weight).mul(risk.priceX18); } } { ( int128 baseAmount, int128 quoteAmount, int128 quoteDeltaAmount ) = _getInLpBalance(productId, subaccount); if (baseAmount != 0) { int128 lpValue = RiskHelper._getLpRawValue( baseAmount, quoteAmount, risk.priceX18 ); health += lpValue.mul( RiskHelper._getWeightX18(risk, 1, healthType) ) + quoteDeltaAmount; } } } } function getCoreRisk( bytes32 subaccount, uint32 productId, IProductEngine.HealthType healthType ) external view returns (IProductEngine.CoreRisk memory) { RiskHelper.Risk memory risk = _risk(productId); (int128 amount, ) = _getBalance(productId, subaccount); return IProductEngine.CoreRisk( amount, risk.priceX18, RiskHelper._getWeightX18(risk, 1, healthType) ); } function _balanceUpdate(uint32 productId, bytes32 subaccount) internal virtual {} function _assertInternal() internal view virtual { require(canApplyDeltas[msg.sender], ERR_UNAUTHORIZED); } function _initialize( address _clearinghouseAddr, address _offchainExchangeAddr, address _endpointAddr, address _admin ) internal initializer { __Ownable_init(); setEndpoint(_endpointAddr); transferOwnership(_admin); _clearinghouse = IClearinghouse(_clearinghouseAddr); canApplyDeltas[_endpointAddr] = true; canApplyDeltas[_clearinghouseAddr] = true; canApplyDeltas[_offchainExchangeAddr] = true; } function getClearinghouse() external view returns (address) { return address(_clearinghouse); } function getProductIds() public view returns (uint32[] memory) { return productIds; } function _addProductForId( uint32 productId, uint32 quoteId, address virtualBook, int128 sizeIncrement, int128 minSize, int128 lpSpreadX18, RiskHelper.RiskStore memory riskStore ) internal { require(virtualBook != address(0)); require( riskStore.longWeightInitial <= riskStore.longWeightMaintenance && riskStore.longWeightMaintenance <= 10**9 && riskStore.shortWeightInitial >= riskStore.shortWeightMaintenance && riskStore.shortWeightMaintenance >= 10**9, ERR_BAD_PRODUCT_CONFIG ); _risk().value[productId] = riskStore; // register product with clearinghouse _clearinghouse.registerProduct(productId); productIds.push(productId); // product ids are in ascending order for (uint256 i = productIds.length - 1; i > 0; i--) { if (productIds[i] < productIds[i - 1]) { uint32 t = productIds[i]; productIds[i] = productIds[i - 1]; productIds[i - 1] = t; } else { break; } } _exchange().updateMarket( productId, quoteId, virtualBook, sizeIncrement, minSize, lpSpreadX18 ); emit AddProduct(productId); } function _exchange() internal view returns (IOffchainExchange) { return IOffchainExchange(IEndpoint(getEndpoint()).getOffchainExchange()); } function updatePrice(uint32 productId, int128 priceX18) external onlyEndpoint { _risk().value[productId].priceX18 = priceX18; } function updateRisk(uint32 productId, RiskHelper.RiskStore memory riskStore) external onlyOwner { require( riskStore.longWeightInitial <= riskStore.longWeightMaintenance && riskStore.shortWeightInitial >= riskStore.shortWeightMaintenance, ERR_BAD_PRODUCT_CONFIG ); _risk().value[productId] = riskStore; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./interfaces/engine/ISpotEngine.sol"; import "./libraries/Logger.sol"; import "./BaseEngine.sol"; abstract contract SpotEngineState is ISpotEngine, BaseEngine { using MathSD21x18 for int128; mapping(uint32 => Config) internal configs; mapping(uint32 => State) internal states; mapping(uint32 => mapping(bytes32 => Balances)) internal balances; mapping(uint32 => LpState) internal lpStates; mapping(uint32 => int128) internal withdrawFees; uint64 public migrationFlag; // deprecated mapping(uint32 => int128) internal minDepositRatesX18; function _updateBalanceWithoutDelta( State memory state, Balance memory balance ) internal pure { if (balance.amount == 0) { balance.lastCumulativeMultiplierX18 = state .cumulativeDepositsMultiplierX18; return; } // Current cumulative multiplier associated with product int128 cumulativeMultiplierX18; if (balance.amount > 0) { cumulativeMultiplierX18 = state.cumulativeDepositsMultiplierX18; } else { cumulativeMultiplierX18 = state.cumulativeBorrowsMultiplierX18; } if (balance.lastCumulativeMultiplierX18 == cumulativeMultiplierX18) { return; } balance.amount = balance.amount.mul(cumulativeMultiplierX18).div( balance.lastCumulativeMultiplierX18 ); balance.lastCumulativeMultiplierX18 = cumulativeMultiplierX18; } function _updateBalance( State memory state, Balance memory balance, int128 balanceDelta ) internal pure { if (balance.amount == 0 && balance.lastCumulativeMultiplierX18 == 0) { balance.lastCumulativeMultiplierX18 = ONE; } if (balance.amount > 0) { state.totalDepositsNormalized -= balance.amount.div( balance.lastCumulativeMultiplierX18 ); } else { state.totalBorrowsNormalized += balance.amount.div( balance.lastCumulativeMultiplierX18 ); } // Current cumulative multiplier associated with product int128 cumulativeMultiplierX18; if (balance.amount > 0) { cumulativeMultiplierX18 = state.cumulativeDepositsMultiplierX18; } else { cumulativeMultiplierX18 = state.cumulativeBorrowsMultiplierX18; } // Apply balance delta and interest rate balance.amount = balance.amount.mul( cumulativeMultiplierX18.div(balance.lastCumulativeMultiplierX18) ) + balanceDelta; if (balance.amount > 0) { cumulativeMultiplierX18 = state.cumulativeDepositsMultiplierX18; } else { cumulativeMultiplierX18 = state.cumulativeBorrowsMultiplierX18; } balance.lastCumulativeMultiplierX18 = cumulativeMultiplierX18; // Update the product given balanceDelta if (balance.amount > 0) { state.totalDepositsNormalized += balance.amount.div( balance.lastCumulativeMultiplierX18 ); } else { state.totalBorrowsNormalized -= balance.amount.div( balance.lastCumulativeMultiplierX18 ); } } function _updateBalanceNormalizedNoTotals( State memory state, BalanceNormalized memory balance, int128 balanceDelta ) internal pure { // dont count X balances in total deposits / borrows // Current cumulative multiplier associated with product int128 cumulativeMultiplierX18; if (balance.amountNormalized > 0) { cumulativeMultiplierX18 = state.cumulativeDepositsMultiplierX18; } else { cumulativeMultiplierX18 = state.cumulativeBorrowsMultiplierX18; } int128 newAmount = balance.amountNormalized.mul( cumulativeMultiplierX18 ) + balanceDelta; if (newAmount > 0) { cumulativeMultiplierX18 = state.cumulativeDepositsMultiplierX18; } else { cumulativeMultiplierX18 = state.cumulativeBorrowsMultiplierX18; } balance.amountNormalized = newAmount.div(cumulativeMultiplierX18); } function _updateBalanceNormalized( State memory state, BalanceNormalized memory balance, int128 balanceDelta ) internal pure { if (balance.amountNormalized > 0) { state.totalDepositsNormalized -= balance.amountNormalized; } else { state.totalBorrowsNormalized += balance.amountNormalized; } _updateBalanceNormalizedNoTotals(state, balance, balanceDelta); // Update the product given balanceDelta if (balance.amountNormalized > 0) { state.totalDepositsNormalized += balance.amountNormalized; } else { state.totalBorrowsNormalized -= balance.amountNormalized; } } function _updateState( uint32 productId, State memory state, uint128 dt ) internal { int128 borrowRateMultiplierX18; int128 totalDeposits = state.totalDepositsNormalized.mul( state.cumulativeDepositsMultiplierX18 ); int128 totalBorrows = state.totalBorrowsNormalized.mul( state.cumulativeBorrowsMultiplierX18 ); int128 utilizationRatioX18 = totalBorrows.div(totalDeposits); { Config memory config = configs[productId]; // annualized borrower rate int128 borrowerRateX18 = config.interestFloorX18; if (utilizationRatioX18 == 0) { // setting borrowerRateX18 to 0 here has the property that // adding a product at the beginning of time and not using it until time T // results in the same state as adding the product at time T borrowerRateX18 = 0; } else if (utilizationRatioX18 < config.interestInflectionUtilX18) { borrowerRateX18 += config .interestSmallCapX18 .mul(utilizationRatioX18) .div(config.interestInflectionUtilX18); } else { borrowerRateX18 += config.interestSmallCapX18 + config.interestLargeCapX18.mul( ( (utilizationRatioX18 - config.interestInflectionUtilX18).div( ONE - config.interestInflectionUtilX18 ) ) ); } // convert to per second borrowerRateX18 = borrowerRateX18.div( MathSD21x18.fromInt(31536000) ); borrowRateMultiplierX18 = (ONE + borrowerRateX18).pow(int128(dt)); } // if we don't take fees into account, the liquidity, which is // (deposits - borrows) should remain the same after updating state. // For simplicity, we use `tb`, `cbm`, `td`, and `cdm` for // `totalBorrowsNormalized`, `cumulativeBorrowsMultiplier`, // `totalDepositsNormalized`, and `cumulativeDepositsMultiplier` // before the updating, the liquidity is (td * cdm - tb * cbm) // after the updating, the liquidity is // (td * cdm * depositRateMultiplier - tb * cbm * borrowRateMultiplier) // so we can get // depositRateMultiplier = utilization * (borrowRateMultiplier - 1) + 1 int128 totalDepositRateX18 = utilizationRatioX18.mul( borrowRateMultiplierX18 - ONE ); // deduct protocol fees int128 realizedDepositRateX18 = totalDepositRateX18.mul( ONE - INTEREST_FEE_FRACTION ); // pass fees balance change int128 feesAmt = totalDeposits.mul( totalDepositRateX18 - realizedDepositRateX18 ); state.cumulativeBorrowsMultiplierX18 = state .cumulativeBorrowsMultiplierX18 .mul(borrowRateMultiplierX18); int128 depositRateMultiplierX18 = ONE + realizedDepositRateX18; state.cumulativeDepositsMultiplierX18 = state .cumulativeDepositsMultiplierX18 .mul(depositRateMultiplierX18); if (feesAmt != 0) { BalanceNormalized memory feesAccBalance = balances[productId][ FEES_ACCOUNT ].balance; _updateBalanceNormalized(state, feesAccBalance, feesAmt); balances[productId][FEES_ACCOUNT].balance = feesAccBalance; _balanceUpdate(productId, FEES_ACCOUNT); } // apply the min deposit rate if (minDepositRatesX18[productId] != 0) { int128 minDepositRatePerSecondX18 = minDepositRatesX18[productId] .div(MathSD21x18.fromInt(31536000)); int128 minDepositRateMultiplierX18 = (ONE + minDepositRatePerSecondX18).pow(int128(dt)); state.cumulativeBorrowsMultiplierX18 = state .cumulativeBorrowsMultiplierX18 .mul(minDepositRateMultiplierX18); state.cumulativeDepositsMultiplierX18 = state .cumulativeDepositsMultiplierX18 .mul(minDepositRateMultiplierX18); depositRateMultiplierX18 = depositRateMultiplierX18.mul( minDepositRateMultiplierX18 ); borrowRateMultiplierX18 = borrowRateMultiplierX18.mul( minDepositRateMultiplierX18 ); } emit InterestPayment( productId, dt, depositRateMultiplierX18, borrowRateMultiplierX18, feesAmt ); } function balanceNormalizedToBalance( State memory state, BalanceNormalized memory balance ) internal pure returns (Balance memory) { int128 cumulativeMultiplierX18; if (balance.amountNormalized > 0) { cumulativeMultiplierX18 = state.cumulativeDepositsMultiplierX18; } else { cumulativeMultiplierX18 = state.cumulativeBorrowsMultiplierX18; } return Balance( balance.amountNormalized.mul(cumulativeMultiplierX18), cumulativeMultiplierX18 ); } // TODO: maybe combine the next two functions // probably also need some protection where quote state must // be fetched through getQuoteState function getStateAndBalance(uint32 productId, bytes32 subaccount) public view returns (State memory, Balance memory) { State memory state = states[productId]; BalanceNormalized memory balance = balances[productId][subaccount] .balance; return (state, balanceNormalizedToBalance(state, balance)); } function getBalance(uint32 productId, bytes32 subaccount) public view returns (Balance memory) { State memory state = states[productId]; BalanceNormalized memory balance = balances[productId][subaccount] .balance; return balanceNormalizedToBalance(state, balance); } function _getBalance(uint32 productId, bytes32 subaccount) internal view override returns (int128, int128) { return (getBalance(productId, subaccount).amount, 0); } function _getInLpBalance(uint32 productId, bytes32 subaccount) internal view virtual override returns ( // baseAmount, quoteAmount, deltaQuoteAmount (funding) int128, int128, int128 ) { LpBalance memory lpBalance = balances[productId][subaccount].lpBalance; if (lpBalance.amount == 0) { return (0, 0, 0); } LpState memory lpState = lpStates[productId]; int128 ratio = lpBalance.amount.div(lpState.supply); int128 baseAmount = lpState.base.amount.mul(ratio); int128 quoteAmount = lpState.quote.amount.mul(ratio); return (baseAmount, quoteAmount, 0); } function getStatesAndBalances(uint32 productId, bytes32 subaccount) external view returns ( LpState memory, LpBalance memory, State memory, Balance memory ) { LpState memory lpState = lpStates[productId]; State memory state = states[productId]; Balances memory bal = balances[productId][subaccount]; LpBalance memory lpBalance = bal.lpBalance; BalanceNormalized memory balance = bal.balance; return ( lpState, lpBalance, state, balanceNormalizedToBalance(state, balance) ); } function updateStates(uint128 dt) external onlyEndpoint { State memory quoteState; require(dt < 7 * SECONDS_PER_DAY, ERR_INVALID_TIME); for (uint32 i = 0; i < productIds.length; i++) { uint32 productId = productIds[i]; State memory state = states[productId]; if (productId == QUOTE_PRODUCT_ID) { quoteState = state; } if (state.totalDepositsNormalized == 0) { continue; } LpState memory lpState = lpStates[productId]; _updateState(productId, state, dt); _updateBalanceWithoutDelta(state, lpState.base); _updateBalanceWithoutDelta(quoteState, lpState.quote); lpStates[productId] = lpState; states[productId] = state; _productUpdate(productId); } } function updateMinDepositRate(uint32 productId, int128 minDepositRateX18) external onlyEndpoint { // deposit rate can't be larger than 100% so that when the rate is incorrectly // set, we still can rescue it without having too much damage. require( minDepositRateX18 >= 0 && minDepositRateX18 <= ONE, ERR_BAD_PRODUCT_CONFIG ); minDepositRatesX18[productId] = minDepositRateX18; } function getMinDepositRate(uint32 productId) external view returns (int128) { return minDepositRatesX18[productId]; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./SpotEngineState.sol"; import "./libraries/Logger.sol"; abstract contract SpotEngineLP is SpotEngineState { using MathSD21x18 for int128; function mintLp( uint32 productId, bytes32 subaccount, int128 amountBase, int128 quoteAmountLow, int128 quoteAmountHigh ) external { _assertInternal(); require( amountBase > 0 && quoteAmountLow > 0 && quoteAmountHigh > 0, ERR_INVALID_LP_AMOUNT ); require( _exchange().getMarketInfo(productId).quoteId == QUOTE_PRODUCT_ID, ERR_INVALID_PRODUCT ); LpState memory lpState = lpStates[productId]; State memory base = states[productId]; State memory quote = states[QUOTE_PRODUCT_ID]; int128 amountQuote = (lpState.base.amount == 0) ? amountBase.mul(_risk(productId).priceX18) : amountBase.mul(lpState.quote.amount.div(lpState.base.amount)); require(amountQuote >= quoteAmountLow, ERR_SLIPPAGE_TOO_HIGH); require(amountQuote <= quoteAmountHigh, ERR_SLIPPAGE_TOO_HIGH); int128 toMint; if (lpState.supply == 0) { toMint = amountBase + amountQuote; } else { toMint = amountBase.div(lpState.base.amount).mul(lpState.supply); } _updateBalance(base, lpState.base, amountBase); _updateBalance(quote, lpState.quote, amountQuote); lpState.supply += toMint; balances[productId][subaccount].lpBalance.amount += toMint; lpStates[productId] = lpState; BalanceNormalized memory baseBalance = balances[productId][subaccount] .balance; BalanceNormalized memory quoteBalance = balances[QUOTE_PRODUCT_ID][ subaccount ].balance; _updateBalanceNormalized(base, baseBalance, -amountBase); _updateBalanceNormalized(quote, quoteBalance, -amountQuote); balances[productId][subaccount].balance = baseBalance; balances[QUOTE_PRODUCT_ID][subaccount].balance = quoteBalance; states[productId] = base; states[QUOTE_PRODUCT_ID] = quote; _balanceUpdate(productId, subaccount); _balanceUpdate(QUOTE_PRODUCT_ID, subaccount); } function burnLp( uint32 productId, bytes32 subaccount, int128 amountLp ) public returns (int128 amountBase, int128 amountQuote) { _assertInternal(); require(amountLp > 0, ERR_INVALID_LP_AMOUNT); LpState memory lpState = lpStates[productId]; LpBalance memory lpBalance = balances[productId][subaccount].lpBalance; State memory base = states[productId]; State memory quote = states[QUOTE_PRODUCT_ID]; if (amountLp == type(int128).max) { amountLp = lpBalance.amount; } if (amountLp == 0) { return (0, 0); } require(lpBalance.amount >= amountLp, ERR_INSUFFICIENT_LP); lpBalance.amount -= amountLp; amountBase = int128( (int256(amountLp) * lpState.base.amount) / lpState.supply ); amountQuote = int128( (int256(amountLp) * lpState.quote.amount) / lpState.supply ); _updateBalance(base, lpState.base, -amountBase); _updateBalance(quote, lpState.quote, -amountQuote); lpState.supply -= amountLp; lpStates[productId] = lpState; balances[productId][subaccount].lpBalance = lpBalance; BalanceNormalized memory baseBalance = balances[productId][subaccount] .balance; BalanceNormalized memory quoteBalance = balances[QUOTE_PRODUCT_ID][ subaccount ].balance; _updateBalanceNormalized(base, baseBalance, amountBase); _updateBalanceNormalized(quote, quoteBalance, amountQuote); balances[productId][subaccount].balance = baseBalance; balances[QUOTE_PRODUCT_ID][subaccount].balance = quoteBalance; states[productId] = base; states[QUOTE_PRODUCT_ID] = quote; _balanceUpdate(productId, subaccount); _balanceUpdate(QUOTE_PRODUCT_ID, subaccount); } function swapLp( uint32 productId, int128 baseDelta, int128 quoteDelta ) external returns (int128, int128) { _assertInternal(); LpState memory lpState = lpStates[productId]; require( MathHelper.isSwapValid( baseDelta, quoteDelta, lpState.base.amount, lpState.quote.amount ), ERR_INVALID_MAKER ); int128 baseDepositsMultiplierX18 = states[productId] .cumulativeDepositsMultiplierX18; int128 quoteDepositsMultiplierX18 = states[QUOTE_PRODUCT_ID] .cumulativeDepositsMultiplierX18; lpState.base.amount += baseDelta; lpState.quote.amount += quoteDelta; lpStates[productId] = lpState; states[productId].totalDepositsNormalized += baseDelta.div( baseDepositsMultiplierX18 ); states[QUOTE_PRODUCT_ID].totalDepositsNormalized += quoteDelta.div( quoteDepositsMultiplierX18 ); _productUpdate(productId); return (baseDelta, quoteDelta); } function decomposeLps(bytes32 liquidatee, bytes32 liquidator) external returns (int128 liquidationFees) { uint32[] memory _productIds = getProductIds(); for (uint128 i = 0; i < _productIds.length; ++i) { uint32 productId = _productIds[i]; (, int128 amountQuote) = burnLp( productId, liquidatee, type(int128).max ); if (amountQuote != 0) { int128 rewards = amountQuote.mul( (ONE - RiskHelper._getWeightX18( _risk(productId), amountQuote, IProductEngine.HealthType.MAINTENANCE )) / 50 ); int128 fees = rewards.mul(LIQUIDATION_FEE_FRACTION); rewards -= fees; liquidationFees += fees; State memory quote = states[QUOTE_PRODUCT_ID]; BalanceNormalized memory liquidateeQuote = balances[ QUOTE_PRODUCT_ID ][liquidatee].balance; BalanceNormalized memory liquidatorQuote = balances[ QUOTE_PRODUCT_ID ][liquidator].balance; _updateBalanceNormalized( quote, liquidateeQuote, -rewards - fees ); _updateBalanceNormalized(quote, liquidatorQuote, rewards); balances[QUOTE_PRODUCT_ID][liquidatee] .balance = liquidateeQuote; balances[QUOTE_PRODUCT_ID][liquidator] .balance = liquidatorQuote; states[QUOTE_PRODUCT_ID] = quote; _balanceUpdate(QUOTE_PRODUCT_ID, liquidator); _balanceUpdate(QUOTE_PRODUCT_ID, liquidatee); } } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../clearinghouse/IClearinghouse.sol"; import "../../libraries/RiskHelper.sol"; interface IProductEngine { event AddProduct(uint32 productId); enum EngineType { SPOT, PERP } enum HealthType { INITIAL, MAINTENANCE, PNL } struct ProductDelta { uint32 productId; bytes32 subaccount; int128 amountDelta; int128 vQuoteDelta; } struct CoreRisk { int128 amount; int128 price; int128 longWeight; } /// @notice Initializes the engine function initialize( address _clearinghouse, address _offchainExchange, address _quote, address _endpoint, address _admin ) external; function getHealthContribution( bytes32 subaccount, IProductEngine.HealthType healthType ) external view returns (int128); function getCoreRisk( bytes32 subaccount, uint32 productId, IProductEngine.HealthType healthType ) external view returns (IProductEngine.CoreRisk memory); function updateProduct(bytes calldata txn) external; function swapLp( uint32 productId, int128 baseDelta, int128 quoteDelta ) external returns (int128, int128); function mintLp( uint32 productId, bytes32 subaccount, int128 amountBase, int128 quoteAmountLow, int128 quoteAmountHigh ) external; function burnLp( uint32 productId, bytes32 subaccount, // passing 0 here means to burn all int128 amountLp ) external returns (int128, int128); function decomposeLps(bytes32 liquidatee, bytes32 liquidator) external returns (int128); /// @notice return clearinghouse addr function getClearinghouse() external view returns (address); /// @notice return productIds associated with engine function getProductIds() external view returns (uint32[] memory); function getRisk(uint32 productId) external view returns (RiskHelper.Risk memory); /// @notice return the type of engine function getEngineType() external pure returns (IProductEngine.EngineType); function updatePrice(uint32 productId, int128 priceX18) external; }
// 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: GPL-2.0-or-later pragma solidity ^0.8.0; interface IClearinghouseEventEmitter { /// @notice Emitted during initialization event ClearinghouseInitialized(address endpoint, address quote); /// @notice Emitted when collateral is modified for a subaccount event ModifyCollateral( int128 amount, bytes32 indexed subaccount, uint32 productId ); event Liquidation( bytes32 indexed liquidatorSubaccount, bytes32 indexed liquidateeSubaccount, uint32 productId, bool isEncodedSpread, int128 amount, int128 amountQuote ); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./clearinghouse/IClearinghouse.sol"; interface IEndpoint { event SubmitTransactions(); // events that we parse transactions into enum TransactionType { LiquidateSubaccount, DepositCollateral, WithdrawCollateral, SpotTick, UpdatePrice, SettlePnl, MatchOrders, DepositInsurance, ExecuteSlowMode, MintLp, BurnLp, SwapAMM, MatchOrderAMM, DumpFees, ClaimSequencerFees, PerpTick, ManualAssert, Rebate, // deprecated UpdateProduct, LinkSigner, UpdateFeeRates, BurnLpAndTransfer, MatchOrdersRFQ, TransferQuote, RebalanceXWithdraw, UpdateMinDepositRate, AssertCode, WithdrawInsurance, CreateIsolatedSubaccount } struct UpdateProduct { address engine; bytes tx; } /// requires signature from sender enum LiquidationMode { SPREAD, SPOT, PERP } struct LegacyLiquidateSubaccount { bytes32 sender; bytes32 liquidatee; uint8 mode; uint32 healthGroup; int128 amount; uint64 nonce; } struct LiquidateSubaccount { bytes32 sender; bytes32 liquidatee; uint32 productId; bool isEncodedSpread; int128 amount; uint64 nonce; } struct LegacySignedLiquidateSubaccount { LegacyLiquidateSubaccount tx; bytes signature; } struct SignedLiquidateSubaccount { LiquidateSubaccount tx; bytes signature; } struct DepositCollateral { bytes32 sender; uint32 productId; uint128 amount; } struct SignedDepositCollateral { DepositCollateral tx; bytes signature; } struct WithdrawCollateral { bytes32 sender; uint32 productId; uint128 amount; uint64 nonce; } struct SignedWithdrawCollateral { WithdrawCollateral tx; bytes signature; } struct MintLp { bytes32 sender; uint32 productId; uint128 amountBase; uint128 quoteAmountLow; uint128 quoteAmountHigh; uint64 nonce; } struct SignedMintLp { MintLp tx; bytes signature; } struct BurnLp { bytes32 sender; uint32 productId; uint128 amount; uint64 nonce; } struct SignedBurnLp { BurnLp tx; bytes signature; } struct LinkSigner { bytes32 sender; bytes32 signer; uint64 nonce; } struct SignedLinkSigner { LinkSigner tx; bytes signature; } /// callable by endpoint; no signature verifications needed struct PerpTick { uint128 time; int128[] avgPriceDiffs; } struct LegacySpotTick { uint128 time; } struct SpotTick { uint128 time; // utilization ratio across all chains int128[] utilizationRatiosX18; } struct ManualAssert { int128[] openInterests; int128[] totalDeposits; int128[] totalBorrows; } struct AssertCode { string[] contractNames; bytes32[] codeHashes; } struct WithdrawInsurance { uint128 amount; address sendTo; } struct Rebate { bytes32[] subaccounts; int128[] amounts; } struct UpdateFeeRates { address user; uint32 productId; // the absolute value of fee rates can't be larger than 100%, // so their X18 values are in the range [-1e18, 1e18], which // can be stored by using int64. int64 makerRateX18; int64 takerRateX18; } struct ClaimSequencerFees { bytes32 subaccount; } struct RebalanceXWithdraw { uint32 productId; uint128 amount; address sendTo; } struct UpdateMinDepositRate { uint32 productId; int128 minDepositRateX18; } struct UpdatePrice { uint32 productId; int128 priceX18; } struct SettlePnl { bytes32[] subaccounts; uint256[] productIds; } /// matching struct Order { bytes32 sender; int128 priceX18; int128 amount; uint64 expiration; uint64 nonce; } struct SignedOrder { Order order; bytes signature; } struct LegacyMatchOrders { uint32 productId; bool amm; SignedOrder taker; SignedOrder maker; } struct MatchOrders { uint32 productId; SignedOrder taker; SignedOrder maker; } struct MatchOrdersWithSigner { MatchOrders matchOrders; address takerLinkedSigner; address makerLinkedSigner; } // just swap against AMM -- theres no maker order struct MatchOrderAMM { uint32 productId; int128 baseDelta; int128 quoteDelta; SignedOrder taker; } struct SwapAMM { bytes32 sender; uint32 productId; int128 amount; int128 priceX18; } struct DepositInsurance { uint128 amount; } struct SlowModeTx { uint64 executableAt; address sender; bytes tx; } struct SlowModeConfig { uint64 timeout; uint64 txCount; uint64 txUpTo; } // legacy :( struct Prices { int128 spotPriceX18; int128 perpPriceX18; } struct BurnLpAndTransfer { bytes32 sender; uint32 productId; uint128 amount; bytes32 recipient; } struct TransferQuote { bytes32 sender; bytes32 recipient; uint128 amount; uint64 nonce; } struct SignedTransferQuote { TransferQuote tx; bytes signature; } struct IsolatedOrder { bytes32 sender; int128 priceX18; int128 amount; uint64 expiration; uint64 nonce; int128 margin; } struct CreateIsolatedSubaccount { IsolatedOrder order; uint32 productId; bytes signature; } function depositCollateral( bytes12 subaccountName, uint32 productId, uint128 amount ) external; function depositCollateralWithReferral( bytes12 subaccountName, uint32 productId, uint128 amount, string calldata referralCode ) external; function depositCollateralWithReferral( bytes32 subaccount, uint32 productId, uint128 amount, string calldata referralCode ) external; function submitSlowModeTransaction(bytes calldata transaction) external; function getTime() external view returns (uint128); function getSequencer() external view returns (address); function getNonce(address sender) external view returns (uint64); function getOffchainExchange() external view returns (address); function getPriceX18(uint32 productId) external view returns (int128); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.13; import "./IEndpoint.sol"; interface IEndpointGated { function getEndpoint() external view returns (address endpoint); }
// 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; /// @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 (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity >= 0.4.22 <0.9.0; library console { address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); function _sendLogPayload(bytes memory payload) private view { uint256 payloadLength = payload.length; address consoleAddress = CONSOLE_ADDRESS; assembly { let payloadStart := add(payload, 32) let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) } } function log() internal view { _sendLogPayload(abi.encodeWithSignature("log()")); } function logInt(int p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); } function logUint(uint p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); } function logString(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function logBool(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function logAddress(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function logBytes(bytes memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); } function logBytes1(bytes1 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); } function logBytes2(bytes2 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); } function logBytes3(bytes3 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); } function logBytes4(bytes4 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); } function logBytes5(bytes5 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); } function logBytes6(bytes6 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); } function logBytes7(bytes7 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); } function logBytes8(bytes8 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); } function logBytes9(bytes9 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); } function logBytes10(bytes10 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); } function logBytes11(bytes11 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); } function logBytes12(bytes12 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); } function logBytes13(bytes13 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); } function logBytes14(bytes14 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); } function logBytes15(bytes15 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); } function logBytes16(bytes16 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); } function logBytes17(bytes17 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); } function logBytes18(bytes18 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); } function logBytes19(bytes19 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); } function logBytes20(bytes20 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); } function logBytes21(bytes21 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); } function logBytes22(bytes22 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); } function logBytes23(bytes23 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); } function logBytes24(bytes24 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); } function logBytes25(bytes25 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); } function logBytes26(bytes26 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); } function logBytes27(bytes27 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); } function logBytes28(bytes28 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); } function logBytes29(bytes29 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); } function logBytes30(bytes30 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); } function logBytes31(bytes31 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); } function logBytes32(bytes32 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); } function log(uint p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); } function log(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function log(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function log(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function log(uint p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); } function log(uint p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); } function log(uint p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); } function log(uint p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); } function log(string memory p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); } function log(string memory p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); } function log(string memory p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); } function log(string memory p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); } function log(bool p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); } function log(bool p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); } function log(bool p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); } function log(bool p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); } function log(address p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); } function log(address p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); } function log(address p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); } function log(address p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); } function log(uint p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); } function log(uint p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); } function log(uint p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); } function log(uint p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); } function log(uint p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); } function log(uint p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); } function log(uint p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); } function log(uint p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); } function log(uint p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); } function log(uint p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); } function log(uint p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); } function log(uint p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); } function log(uint p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); } function log(uint p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); } function log(uint p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); } function log(uint p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); } function log(string memory p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); } function log(string memory p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); } function log(string memory p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); } function log(string memory p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); } function log(string memory p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); } function log(string memory p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); } function log(string memory p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); } function log(string memory p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); } function log(string memory p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); } function log(string memory p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); } function log(string memory p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); } function log(string memory p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); } function log(string memory p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); } function log(string memory p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); } function log(string memory p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); } function log(string memory p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); } function log(bool p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); } function log(bool p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); } function log(bool p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); } function log(bool p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); } function log(bool p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); } function log(bool p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); } function log(bool p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); } function log(bool p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); } function log(bool p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); } function log(bool p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); } function log(bool p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); } function log(bool p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); } function log(bool p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); } function log(bool p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); } function log(bool p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); } function log(bool p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); } function log(address p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); } function log(address p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); } function log(address p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); } function log(address p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); } function log(address p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); } function log(address p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); } function log(address p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); } function log(address p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); } function log(address p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); } function log(address p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); } function log(address p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); } function log(address p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); } function log(address p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); } function log(address p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); } function log(address p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); } function log(address p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); } function log(uint p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./clearinghouse/IClearinghouse.sol"; interface IOffchainExchange { event FillOrder( uint32 indexed productId, // original order information bytes32 indexed digest, bytes32 indexed subaccount, int128 priceX18, int128 amount, uint64 expiration, uint64 nonce, // whether this order is taking or making bool isTaker, // amount paid in fees (in quote) int128 feeAmount, // change in this subaccount's base balance from this fill int128 baseDelta, // change in this subaccount's quote balance from this fill int128 quoteDelta ); struct FeeRates { int64 makerRateX18; int64 takerRateX18; uint8 isNonDefault; // 1: non-default, 0: default } struct LpParams { int128 lpSpreadX18; } struct MarketInfoStore { int64 minSize; int64 sizeIncrement; int128 collectedFees; } struct MarketInfo { uint32 quoteId; int128 minSize; int128 sizeIncrement; int128 collectedFees; } function initialize(address _clearinghouse, address _endpoint) external; function updateFeeRates( address user, uint32 productId, int64 makerRateX18, int64 takerRateX18 ) external; function updateMarket( uint32 productId, uint32 quoteId, address virtualBook, int128 sizeIncrement, int128 minSize, int128 lpSpreadX18 ) external; function getMinSize(uint32 productId) external view returns (int128); function getDigest(uint32 productId, IEndpoint.Order memory order) external view returns (bytes32); function getSizeIncrement(uint32 productId) external view returns (int128); function getMarketInfo(uint32 productId) external view returns (MarketInfo memory); function getLpParams(uint32 productId) external view returns (LpParams memory); function swapAMM(IEndpoint.SwapAMM calldata tx) external; function matchOrderAMM( IEndpoint.MatchOrderAMM calldata tx, address takerLinkedSigner ) external; function matchOrders(IEndpoint.MatchOrdersWithSigner calldata tx) external; function dumpFees() external; function createIsolatedSubaccount( IEndpoint.CreateIsolatedSubaccount memory tx, address linkedSigner ) external returns (bytes32); function isIsolatedSubaccountActive(bytes32 parent, bytes32 subaccount) external view returns (bool); function getParentSubaccount(bytes32 subaccount) external view returns (bytes32); function tryCloseIsolatedSubaccount(bytes32 subaccount) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "./interfaces/IEndpoint.sol"; import "./interfaces/IEndpointGated.sol"; import "./libraries/MathSD21x18.sol"; import "./common/Constants.sol"; import "hardhat/console.sol"; abstract contract EndpointGated is OwnableUpgradeable, IEndpointGated { address private endpoint; function setEndpoint(address _endpoint) internal onlyOwner { endpoint = _endpoint; } function getEndpoint() public view returns (address) { return endpoint; } function getOracleTime() internal view returns (uint128) { return IEndpoint(endpoint).getTime(); } modifier onlyEndpoint() { require( msg.sender == endpoint, "SequencerGated: caller is not the endpoint" ); _; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Strings.sol"; import "./MathHelper.sol"; library Logger { event VertexEVMLog(string message); function log(string memory message) internal { emit VertexEVMLog(message); } function log(int128 value) internal { log(MathHelper.int2str(value)); } function log(string memory message, int128 value) internal { log(string.concat(message, " ", MathHelper.int2str(value))); } function log(string memory message, uint128 value) internal { log(string.concat(message, " ", MathHelper.uint2str(value))); } // function log(string memory message, uint32 value) internal { // log(message, uint128(value)); // } function log(string memory message, address value) internal { log( string.concat(message, " ", Strings.toHexString(uint160(value), 20)) ); } function log(string memory messages, bytes32 value) internal { log(string.concat(messages, " ", string(abi.encodePacked(value)))); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Internal function that returns the initialized version. Returns `_initialized` */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Internal function that returns the initialized version. Returns `_initializing` */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 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-rc.2) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (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); } } }
{ "optimizer": { "enabled": true, "runs": 40 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"productId","type":"uint32"}],"name":"AddProduct","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"productId","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"subaccount","type":"bytes32"}],"name":"BalanceUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"productId","type":"uint32"},{"indexed":false,"internalType":"uint128","name":"dt","type":"uint128"},{"indexed":false,"internalType":"int128","name":"depositRateMultiplierX18","type":"int128"},{"indexed":false,"internalType":"int128","name":"borrowRateMultiplierX18","type":"int128"},{"indexed":false,"internalType":"int128","name":"feeAmount","type":"int128"}],"name":"InterestPayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"productId","type":"uint32"}],"name":"ProductUpdate","type":"event"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"uint32","name":"quoteId","type":"uint32"},{"internalType":"address","name":"book","type":"address"},{"internalType":"int128","name":"sizeIncrement","type":"int128"},{"internalType":"int128","name":"minSize","type":"int128"},{"internalType":"int128","name":"lpSpreadX18","type":"int128"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"int128","name":"interestInflectionUtilX18","type":"int128"},{"internalType":"int128","name":"interestFloorX18","type":"int128"},{"internalType":"int128","name":"interestSmallCapX18","type":"int128"},{"internalType":"int128","name":"interestLargeCapX18","type":"int128"}],"internalType":"struct ISpotEngine.Config","name":"config","type":"tuple"},{"components":[{"internalType":"int32","name":"longWeightInitial","type":"int32"},{"internalType":"int32","name":"shortWeightInitial","type":"int32"},{"internalType":"int32","name":"longWeightMaintenance","type":"int32"},{"internalType":"int32","name":"shortWeightMaintenance","type":"int32"},{"internalType":"int128","name":"priceX18","type":"int128"}],"internalType":"struct RiskHelper.RiskStore","name":"riskStore","type":"tuple"}],"name":"addProduct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"assertUtilization","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"internalType":"int128","name":"amountLp","type":"int128"}],"name":"burnLp","outputs":[{"internalType":"int128","name":"amountBase","type":"int128"},{"internalType":"int128","name":"amountQuote","type":"int128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"liquidatee","type":"bytes32"},{"internalType":"bytes32","name":"liquidator","type":"bytes32"}],"name":"decomposeLps","outputs":[{"internalType":"int128","name":"liquidationFees","type":"int128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"bytes32","name":"subaccount","type":"bytes32"}],"name":"getBalance","outputs":[{"components":[{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"int128","name":"lastCumulativeMultiplierX18","type":"int128"}],"internalType":"struct ISpotEngine.Balance","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClearinghouse","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getConfig","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"int128","name":"interestInflectionUtilX18","type":"int128"},{"internalType":"int128","name":"interestFloorX18","type":"int128"},{"internalType":"int128","name":"interestSmallCapX18","type":"int128"},{"internalType":"int128","name":"interestLargeCapX18","type":"int128"}],"internalType":"struct ISpotEngine.Config","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"enum IProductEngine.HealthType","name":"healthType","type":"uint8"}],"name":"getCoreRisk","outputs":[{"components":[{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"int128","name":"price","type":"int128"},{"internalType":"int128","name":"longWeight","type":"int128"}],"internalType":"struct IProductEngine.CoreRisk","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEndpoint","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEngineType","outputs":[{"internalType":"enum IProductEngine.EngineType","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"internalType":"enum IProductEngine.HealthType","name":"healthType","type":"uint8"}],"name":"getHealthContribution","outputs":[{"internalType":"int128","name":"health","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getMinDepositRate","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProductIds","outputs":[{"internalType":"uint32[]","name":"","type":"uint32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getRisk","outputs":[{"components":[{"internalType":"int128","name":"longWeightInitialX18","type":"int128"},{"internalType":"int128","name":"shortWeightInitialX18","type":"int128"},{"internalType":"int128","name":"longWeightMaintenanceX18","type":"int128"},{"internalType":"int128","name":"shortWeightMaintenanceX18","type":"int128"},{"internalType":"int128","name":"priceX18","type":"int128"}],"internalType":"struct RiskHelper.Risk","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"bytes32","name":"subaccount","type":"bytes32"}],"name":"getStateAndBalance","outputs":[{"components":[{"internalType":"int128","name":"cumulativeDepositsMultiplierX18","type":"int128"},{"internalType":"int128","name":"cumulativeBorrowsMultiplierX18","type":"int128"},{"internalType":"int128","name":"totalDepositsNormalized","type":"int128"},{"internalType":"int128","name":"totalBorrowsNormalized","type":"int128"}],"internalType":"struct ISpotEngine.State","name":"","type":"tuple"},{"components":[{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"int128","name":"lastCumulativeMultiplierX18","type":"int128"}],"internalType":"struct ISpotEngine.Balance","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"bytes32","name":"subaccount","type":"bytes32"}],"name":"getStatesAndBalances","outputs":[{"components":[{"internalType":"int128","name":"supply","type":"int128"},{"components":[{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"int128","name":"lastCumulativeMultiplierX18","type":"int128"}],"internalType":"struct ISpotEngine.Balance","name":"quote","type":"tuple"},{"components":[{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"int128","name":"lastCumulativeMultiplierX18","type":"int128"}],"internalType":"struct ISpotEngine.Balance","name":"base","type":"tuple"}],"internalType":"struct ISpotEngine.LpState","name":"","type":"tuple"},{"components":[{"internalType":"int128","name":"amount","type":"int128"}],"internalType":"struct ISpotEngine.LpBalance","name":"","type":"tuple"},{"components":[{"internalType":"int128","name":"cumulativeDepositsMultiplierX18","type":"int128"},{"internalType":"int128","name":"cumulativeBorrowsMultiplierX18","type":"int128"},{"internalType":"int128","name":"totalDepositsNormalized","type":"int128"},{"internalType":"int128","name":"totalBorrowsNormalized","type":"int128"}],"internalType":"struct ISpotEngine.State","name":"","type":"tuple"},{"components":[{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"int128","name":"lastCumulativeMultiplierX18","type":"int128"}],"internalType":"struct ISpotEngine.Balance","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getWithdrawFee","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_clearinghouse","type":"address"},{"internalType":"address","name":"_offchainExchange","type":"address"},{"internalType":"address","name":"_quote","type":"address"},{"internalType":"address","name":"_endpoint","type":"address"},{"internalType":"address","name":"_admin","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int128[]","name":"totalDeposits","type":"int128[]"},{"internalType":"int128[]","name":"totalBorrows","type":"int128[]"}],"name":"manualAssert","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrationFlag","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"internalType":"int128","name":"amountBase","type":"int128"},{"internalType":"int128","name":"quoteAmountLow","type":"int128"},{"internalType":"int128","name":"quoteAmountHigh","type":"int128"}],"name":"mintLp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subaccount","type":"bytes32"}],"name":"socializeSubaccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"int128","name":"baseDelta","type":"int128"},{"internalType":"int128","name":"quoteDelta","type":"int128"}],"name":"swapLp","outputs":[{"internalType":"int128","name":"","type":"int128"},{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"internalType":"int128","name":"amountDelta","type":"int128"}],"name":"updateBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"internalType":"int128","name":"amountDelta","type":"int128"},{"internalType":"int128","name":"quoteDelta","type":"int128"}],"name":"updateBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"int128","name":"minDepositRateX18","type":"int128"}],"name":"updateMinDepositRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"int128","name":"priceX18","type":"int128"}],"name":"updatePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"rawTxn","type":"bytes"}],"name":"updateProduct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"internalType":"int128","name":"insurance","type":"int128"}],"name":"updateQuoteFromInsurance","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"components":[{"internalType":"int32","name":"longWeightInitial","type":"int32"},{"internalType":"int32","name":"shortWeightInitial","type":"int32"},{"internalType":"int32","name":"longWeightMaintenance","type":"int32"},{"internalType":"int32","name":"shortWeightMaintenance","type":"int32"},{"internalType":"int128","name":"priceX18","type":"int128"}],"internalType":"struct RiskHelper.RiskStore","name":"riskStore","type":"tuple"}],"name":"updateRisk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"dt","type":"uint128"}],"name":"updateStates","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50615cf780620000216000396000f3fe608060405234801561001057600080fd5b50600436106101b15760003560e01c8063aed8e967116100f5578063aed8e96714610397578063b1cb0f42146103a8578063b8d80d8b146103b9578063c362d19e146103cc578063c55607b5146103f7578063c7167cf51461040a578063c9fe9ac314610437578063d386c1e81461044a578063d98752ec1461045d578063e0b0621f14610470578063e334be3314610483578063e343738c146104a4578063ec6271d2146105a0578063ecd9cba8146105b3578063f2fde38b14610617578063f39eeb101461062a578063f8a42e511461063d578063fdf4a0c01461065057600080fd5b8063130ea373146101b65780631459457a146101f7578063153ca6c01461020c57806330972b501461021f5780633d5cc9dc1461023257806345be7ed6146102555780634604d19b1461029c57806347428e7b146102ab5780634ac8d8c1146102c0578063715018a6146102d35780637c1e1487146102db578063871d0912146102fb5780638936f7cd1461030e5780638a1d43c9146103215780638da5cb5b1461036057806398de72fe14610371578063ad733b8e14610384575b600080fd5b6101df6101c4366004614d56565b63ffffffff16600090815260716020526040902054600f0b90565b604051600f9190910b81526020015b60405180910390f35b61020a610205366004614d88565b610663565b005b61020a61021a366004614e08565b610927565b61020a61022d366004614e85565b61099a565b610245610240366004614ef0565b610b7b565b6040516101ee9493929190614f66565b610284610263366004614d56565b63ffffffff166000908152606b60205260409020546001600160a01b031690565b6040516001600160a01b0390911681526020016101ee565b60006040516101ee9190614fdd565b6102b3610cb1565b6040516101ee9190615005565b61020a6102ce366004614d56565b610d35565b61020a610dcc565b6102ee6102e9366004614ef0565b610de0565b6040516101ee919061504f565b6101df61030936600461506c565b610e6b565b61020a61031c366004615098565b610fed565b61033461032f3660046150b1565b611461565b604080518251600f90810b8252602080850151820b908301529282015190920b908201526060016101ee565b6033546001600160a01b0316610284565b61020a61037f3660046150ef565b6114d6565b61020a610392366004615149565b611a6c565b6065546001600160a01b0316610284565b6066546001600160a01b0316610284565b6101df6103c7366004615172565b611d0c565b6070546103df906001600160401b031681565b6040516001600160401b0390911681526020016101ee565b61020a61040536600461527f565b611f5d565b61041d6104183660046152ac565b612075565b60408051600f93840b81529190920b6020820152016101ee565b61020a6104453660046152f7565b6122f5565b61020a61045836600461537a565b612627565b61041d61046b366004615420565b612938565b61020a61047e366004615420565b612f3c565b610496610491366004614ef0565b61303a565b6040516101ee929190615457565b61054a6104b2366004614d56565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091525063ffffffff166000908152606b6020908152604091829020825160a08101845281546001600160a01b031681526001820154600f81810b94830194909452600160801b90819004840b9482019490945260029091015480830b606083015292909204900b608082015290565b6040516101ee9190600060a08201905060018060a01b0383511682526020830151600f0b60208301526040830151600f0b60408301526060830151600f0b60608301526080830151600f0b608083015292915050565b61020a6105ae366004614e08565b6130d1565b6105c66105c1366004614d56565b61318c565b6040516101ee9190600060a0820190508251600f0b82526020830151600f0b60208301526040830151600f0b60408301526060830151600f0b60608301526080830151600f0b608083015292915050565b61020a610625366004615472565b61319d565b6101df61063836600461548f565b613216565b61020a61064b3660046154b4565b613389565b6101df61065e366004614d56565b6135b8565b61066f8585848461368d565b6040805160a080820183526001600160a01b038681168352670b1a2bc2ec5000006020808501918252662386f26fc10000858701908152668e1bc9bf0400006060808801918252670de0b6b3a76400006080808a0182815260008052606b875299517fc8cc8bda7ad4886bea3ebbdafa02e79d37c39bf4011696b26a31a0802fd9458b80546001600160a01b0319169190991617909755945192516001600160801b03938416600160801b9185168202177fc8cc8bda7ad4886bea3ebbdafa02e79d37c39bf4011696b26a31a0802fd9458c55915197519783169790921602959095177fc8cc8bda7ad4886bea3ebbdafa02e79d37c39bf4011696b26a31a0802fd9458d5585519384018652633b9aca0080855290840181905294830185905292820193909352918201526107a2613809565b6000808052602091825260408082208451815486860151878501516060808a015160809a8b01516001600160801b03908116600160801b90810263ffffffff938416600160601b0263ffffffff60601b19968516600160401b0296909616600160401b600160801b0319978516600160201b026001600160401b0319909916998516999099179790971795909516969096179290921785169390931790945584519788018552670de0b6b3a7640000808952888801908152888601878152928901878152878052606c8952985190518416820290841617600080516020615c828339815191525590519651821602951694909417600080516020615ca28339815191525560688054600181018255908352600881047fa2153420d844928b4421650203c77babc8b33d7f2e7b450e2966db0c2209775301805460079092166004026101000a909502191690935591519182527f3286b0394bf1350245290b7226c92ed186bd716f28938e62dbb895298f01817291015b60405180910390a15050505050565b6065546001600160a01b0316331461095a5760405162461bcd60e51b815260040161095190615507565b60405180910390fd5b80610963613809565b63ffffffff9093166000908152602093909352604090922080546001600160801b03938416600160801b0293169290921790915550565b60005b6001600160801b038116841115610b745760006068826001600160801b0316815481106109cc576109cc615551565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff16808352606c825260409283902083516080810185528154600f81810b8352600160801b91829004810b9583019590955260019092015480850b95820195909552930490910b6060830152915086866001600160801b038516818110610a5857610a58615551565b9050602002016020810190610a6d9190615567565b600f0b610a8e82600001518360400151600f0b61382d90919063ffffffff16565b600f0b14604051806040016040528060058152602001644453594e4360d81b81525090610ace5760405162461bcd60e51b81526004016109519190615584565b508484846001600160801b0316818110610aea57610aea615551565b9050602002016020810190610aff9190615567565b600f0b610b2082602001518360600151600f0b61382d90919063ffffffff16565b600f0b14604051806040016040528060058152602001644453594e4360d81b81525090610b605760405162461bcd60e51b81526004016109519190615584565b50505080610b6d906155ef565b905061099d565b5050505050565b610b83614ca9565b604080516020810190915260008152610b9a614cd8565b610ba2614cff565b63ffffffff86166000818152606e602090815260408083208151606080820184528254600f90810b83528451808601865260018086015480840b8352600160801b90819004840b838a0152858901929092528651808801885260029096015480840b8752829004830b8689015284870195909552888852606c87528588208651608081018852815480850b8252839004840b818a01529086015480840b8289015291909104820b81840152978752606d86528487208d8852865295849020845191820185528054870b828601908152825284518087019095529092015490940b82529182018190528151929392848285610c9c81856138a7565b929e919d509b50909950975050505050505050565b60606068805480602002602001604051908101604052809291908181526020018280548015610d2b57602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411610cee5790505b5050505050905090565b6000610d4282600161303a565b5090506000610d6582600001518360400151600f0b61382d90919063ffffffff16565b90506000610d8783602001518460600151600f0b61382d90919063ffffffff16565b905080600f0b82600f0b1215604051806040016040528060028152602001614d5560f01b81525090610b745760405162461bcd60e51b81526004016109519190615584565b610dd4613902565b610dde600061395c565b565b610de8614cff565b63ffffffff83166000818152606c6020908152604080832081516080810183528154600f81810b8352600160801b91829004810b8387015260019093015480840b8386015204820b6060820152948452606d835281842087855283529281902081519283019091525490910b8152610e6082826138a7565b925050505b92915050565b600080610e76610cb1565b90506000610e82613809565b905060005b82518163ffffffff161015610fe4576000838263ffffffff1681518110610eb057610eb0615551565b602002602001015190506000610ec682856139ae565b9050600080610ed5848b613a9f565b915091506000610ee684848c613ab8565b9050610ef2828a61561d565b985082600f0b600014610f6357610f12670de0b6b3a7640000600261566e565b600f0b81600f0b03610f365760016001607f1b031998505050505050505050610e65565b6080840151610f5690610f4d600f86900b8461382d565b600f0b9061382d565b610f60908a61561d565b98505b5050506000806000610f75858c613b4f565b92509250925082600f0b600014610fcc576000610f9784848760800151613c6a565b905081610fb4610fa98760018f613ab8565b600f84900b9061382d565b610fbe919061561d565b610fc8908b61561d565b9950505b50505050508080610fdc90615702565b915050610e87565b50505092915050565b6066546040805180820190915260018152605560f81b6020820152906001600160a01b031633146110315760405162461bcd60e51b81526004016109519190615584565b50600061103c610cb1565b905060005b8151816001600160801b0316101561145c57600082826001600160801b03168151811061107057611070615551565b60209081029190910181015163ffffffff81166000818152606c8452604080822081516080810183528154600f81810b8352600160801b91829004810b838a015260019093015480840b8386015204820b6060820152938352606d86528183208a8452865281832082519687019092529054900b8452919350916110f59083906138a7565b905060008160000151600f0b1215611448578151604083015160009161111e91600f0b9061382d565b6040840151835191925061113f91611136908461561d565b600f0b90613ca6565b600f0b80845260001261115157600080fd5b61116f83602001518360000151600f0b613ca690919063ffffffff16565b83606001818151611180919061561d565b600f0b90525063ffffffff84166000818152606d602090815260408083208b8452909152902080546001600160801b03191690556113085760005b86518163ffffffff161015611302576000878263ffffffff16815181106111e4576111e4615551565b60200260200101519050600063ffffffff168163ffffffff160361120857506112f2565b63ffffffff81166000908152606e602090815260409182902082516060810184528154600f90810b825284518086018652600184015480830b8252600160801b90819004830b828701528386019182528651808801885260029095015480840b86520490910b938301939093529283015251611285908790613d0f565b63ffffffff82166000908152606e6020908152604091829020835181546001600160801b0319166001600160801b0391821617825584830151805190840151908216600160801b918316820217600184015593850151805193015192811692169092021760029091015550505b6112fb81615702565b90506111bb565b506113f7565b63ffffffff84166000908152606e602090815260409182902082516060810184528154600f90810b825284518086018652600184015480830b8252600160801b90819004830b82870152838601919091528551808701875260029094015480830b855204900b9282019290925291810182905290611387908590613d0f565b63ffffffff85166000908152606e6020908152604091829020835181546001600160801b039182166001600160801b0319909116178255848301518051908401518216600160801b9081029183169190911760018401559490930151805192015183169093029116176002909101555b63ffffffff84166000908152606c60209081526040918290208551918601516001600160801b03928316600160801b9184168202178255928601516060870151908316921690920217600190910155505b50505080611455906155ef565b9050611041565b505050565b604080516060810182526000808252602082018190529181018290529061148784613d88565b905060006114958587613a9f565b509050604051806060016040528082600f0b81526020018360800151600f0b81526020016114c584600188613ab8565b600f0b9052925050505b9392505050565b6114de613da1565b600083600f0b1380156114f45750600082600f0b135b80156115035750600081600f0b135b60405180604001604052806003815260200162494c4160e81b8152509061153d5760405162461bcd60e51b81526004016109519190615584565b506000611548613ded565b604051631d029b4d60e01b815263ffffffff881660048201526001600160a01b039190911690631d029b4d90602401608060405180830381865afa158015611594573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b8919061571b565b6000015163ffffffff161460405180604001604052806002815260200161049560f41b815250906115fc5760405162461bcd60e51b81526004016109519190615584565b5063ffffffff85166000818152606e602090815260408083208151606080820184528254600f90810b83528451808601865260018086015480840b8352600160801b90819004840b838a0152858901929092528651808801885260029096015480840b8752829004830b86890152848701958652988852606c808852868920875160808082018a52825480870b8352859004860b828c015291909b015480850b8c8a0152839004840b8b86015289805290885286519081018752600080516020615c828339815191525480840b8252829004830b97810197909752600080516020615ca28339815191525480830b96880196909652909404840b90850152905151909493910b156117345760408401515160208501515161172f9161172491600f0b90613ca6565b600f89900b9061382d565b61174f565b61174f6117408a613d88565b60800151600f89900b9061382d565b905085600f0b81600f0b1215604051806040016040528060038152602001620a6a8960eb1b815250906117955760405162461bcd60e51b81526004016109519190615584565b5084600f0b81600f0b1315604051806040016040528060038152602001620a6a8960eb1b815250906117da5760405162461bcd60e51b81526004016109519190615584565b508351600090600f0b81036117fa576117f3828961561d565b9050611819565b84516040860151516118169190610f4d90600f8c900b90613ca6565b90505b6118288486604001518a613e67565b61183783866020015184613e67565b8085600001818151611849919061561d565b600f90810b90915263ffffffff8c166000908152606d602090815260408083208e84529091528120600101805485945090926118879185910b61561d565b82546101009290920a6001600160801b0381810219909316918316021790915563ffffffff8c166000908152606e602090815260408083208a5181546001600160801b0319169086161781558a830151805190840151908616600160801b91871682021760018301558b83015180519085015190871696160294909417600290940193909355606d81528282208d83528152828220835180830185529054600f90810b82528e8452600080516020615c628339815191528352928490208451928301909452925490910b815290915061196986836119648d6157ad565b61400e565b6119778582611964876157ad565b63ffffffff909b166000818152606d602090815260408083208e84528252808320945185546001600160801b039182166001600160801b0319918216179096559d8352600080516020615c6283398151915282528083209e518f54908f16951694909417909d55908152606c8c528181208651878e01518d16600160801b908102918e16919091178255878401516060988901518e168202908e16176001929092019190915590805284519b8501518b1681029b8b169b909b17600080516020615c828339815191525583015192909301518816909802961695909517600080516020615ca283398151915255505050505050565b6065546001600160a01b03163314611a965760405162461bcd60e51b815260040161095190615507565b611a9e614cd8565b611aac6201518060076157d0565b6001600160401b0316826001600160801b0316106040518060400160405280600381526020016249544960e81b81525090611afa5760405162461bcd60e51b81526004016109519190615584565b5060005b60685463ffffffff8216101561145c57600060688263ffffffff1681548110611b2957611b29615551565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff16808352606c825260409283902083516080810185528154600f81810b8352600160801b91829004810b9583019590955260019092015480850b95820195909552930490910b6060830152915081611ba3578093505b8060400151600f0b600003611bb9575050611cfa565b63ffffffff82166000908152606e602090815260409182902082516060810184528154600f90810b825284518086018652600184015480830b8252600160801b90819004830b82870152838601919091528551808701875260029094015480830b855204900b9282019290925291810191909152611c388383886140a2565b611c46828260400151613d0f565b611c54858260200151613d0f565b63ffffffff83166000908152606e60209081526040808320845181546001600160801b0319166001600160801b0391821617825585840151805190850151908216600160801b91831682021760018085019190915587850151805190870151908416908416830217600290940193909355606c85529483902087519488015194821694821686029490941784559186015160608701519083169216909302179101555050505b80611d0481615702565b915050611afe565b600080611d17610cb1565b905060005b8151816001600160801b03161015611f5557600082826001600160801b031681518110611d4b57611d4b615551565b602002602001015190506000611d69828860016001607f1b03612938565b91505080600f0b600014611f42576000611dae6032611d92611d8a86613d88565b856001613ab8565b611da490670de0b6b3a76400006157ff565b610fa99190615865565b90506000611dc8600f83900b6706f05b59d3b2000061382d565b9050611dd481836157ff565b9150611de0818861561d565b60408051608081018252600080516020615c8283398151915254600f81810b8352600160801b91829004810b602084810191909152600080516020615ca28339815191525480830b8587015292909204810b606084015260008e8152600080516020615c62833981519152808452858220865180860188529054840b81528f83529084529085902085519384019095529354900b815292995091611e93838386611e89896157ad565b61196491906157ff565b611e9e83828761400e565b60008c8152600080516020615c6283398151915260209081526040808320945185546001600160801b039182166001600160801b0319918216179096558e845281842094518554908216961695909517909355908052606c81528351908401518316600160801b90810291841691909117600080516020615c828339815191525590830151606090930151821602911617600080516020615ca28339815191525550505b505080611f4e906155ef565b9050611d1c565b505092915050565b611f65613902565b806040015160030b816000015160030b13158015611f915750806060015160030b816020015160030b12155b6040518060400160405280600381526020016242504360e81b81525090611fcb5760405162461bcd60e51b81526004016109519190615584565b5080611fd5613809565b63ffffffff9384166000908152602091825260409081902083518154938501519285015160608601516080909601516001600160801b03908116600160801b02968916600160601b0263ffffffff60601b19928a16600160401b0292909216600160401b600160801b0319958a16600160201b026001600160401b0319909716939099169290921794909417929092169590951791909117161790915550565b600080612080613da1565b63ffffffff85166000908152606e602090815260409182902082516060810184528154600f90810b825284518086018652600184015480830b8252600160801b90819004830b828701528386019182528651808801885260029095015480840b86520490910b93830193909352928301819052519051516121059187918791906144a1565b60405180604001604052806002815260200161494d60f01b8152509061213e5760405162461bcd60e51b81526004016109519190615584565b5063ffffffff86166000908152606c602052604080822054918052600080516020615c8283398151915254908301518051600f93840b939290920b9188919061218890839061561d565b600f0b905250602083015180518791906121a390839061561d565b600f90810b90915263ffffffff8a81166000908152606e6020908152604091829020885181546001600160801b0319166001600160801b0391821617825589830151805190840151908216600160801b9183168202176001840155938a0151805193015192811692169092021760029091015561222892509089900b908490613ca616565b63ffffffff89166000908152606c602052604081206001018054909190612253908490600f0b61561d565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055506122908187600f0b613ca690919063ffffffff16565b6000808052606c602052600080516020615ca283398151915280549091906122bc908490600f0b61561d565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508686945094505050505b935093915050565b6065546001600160a01b0316331461231f5760405162461bcd60e51b815260040161095190615507565b600061232d828401846158a3565b60a081015181519192509063ffffffff16156125a557806040015160030b816000015160030b1315801561236f5750806060015160030b816020015160030b12155b80156123a25750608082015151825163ffffffff166000908152606b60205260409020546001600160a01b039081169116145b6040518060400160405280600381526020016242504360e81b815250906123dc5760405162461bcd60e51b81526004016109519190615584565b5060006123e7613809565b835163ffffffff1660009081526020918252604090819020815160a0810183529054600381810b8352600160201b8204810b838601908152600160401b8304820b848601908152600160601b8404830b6060808701918252600160801b909504600f0b60808701528951840b865296890151830b90915293870151810b90935285015190910b90915290508061247b613809565b845163ffffffff9081166000908152602092835260409081902084518154948601519286015160608701516080909701516001600160801b03908116600160801b02978616600160601b0263ffffffff60601b19928716600160401b0292909216600160401b600160801b0319958716600160201b026001600160401b031990981693909616929092179590951792909216929092179290921791909116919091179055612527613ded565b6001600160a01b0316632da1c59b846000015163ffffffff60008760200151886040015189606001516040518763ffffffff1660e01b8152600401612571969594939291906159a1565b600060405180830381600087803b15801561258b57600080fd5b505af115801561259f573d6000803e3d6000fd5b50505050505b50608081810151915163ffffffff166000908152606b6020908152604091829020845181546001600160a01b0319166001600160a01b0390911617815590840151918401516001600160801b03928316600160801b91841682021760018301556060850151949093015193821693909116909102919091176002909101555050565b61262f613902565b63ffffffff881661263f57600080fd5b61265c888888888888612657368990038901896159e6565b61453f565b63ffffffff88166000908152606b60205260409020829061267d8282615a45565b9050506040518060800160405280670de0b6b3a7640000600f0b8152602001670de0b6b3a7640000600f0b81526020016000600f0b81526020016000600f0b815250606c60008a63ffffffff1663ffffffff16815260200190815260200160002060008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060408201518160010160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060608201518160010160106101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555090505060405180606001604052806000600f0b815260200160405180604001604052806000600f0b8152602001670de0b6b3a7640000600f0b815250815260200160405180604001604052806000600f0b8152602001670de0b6b3a7640000600f0b815250815250606e60008a63ffffffff1663ffffffff16815260200190815260200160002060008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160010160008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b03160217905550505060408201518160020160008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555050509050505050505050505050565b600080612943613da1565b600083600f0b1360405180604001604052806003815260200162494c4160e81b815250906129845760405162461bcd60e51b81526004016109519190615584565b5063ffffffff85166000818152606e602090815260408083208151606080820184528254600f90810b83528451808601865260018086015480840b8352600160801b90819004840b838a0152858901929092528651808801885260029096015480840b8752829004830b8689015284870195909552888852606d87528588208d895287528588208651808901885290860154830b8152988852606c808852868920875160808082018a52825480870b8352859004860b828c0152919097015480850b888a0152839004840b87860152988052875285519788018652600080516020615c828339815191525480830b8952819004820b96880196909652600080516020615ca28339815191525480820b9588019590955294909304840b92850192909252909392909187900b60026001607f1b031901612ac257825196505b86600f0b600003612add5760008095509550505050506122ed565b86600f0b8360000151600f0b1215604051806040016040528060038152602001620494c560ec1b81525090612b255760405162461bcd60e51b81526004016109519190615584565b508683600001818151612b3891906157ff565b600f90810b909152855160408701515190820b9250612b5d9190810b908a900b615ad7565b612b679190615b5c565b95508360000151600f0b846020015160000151600f0b88600f0b612b8b9190615ad7565b612b959190615b5c565b9450612baf82856040015188612baa906157ad565b613e67565b612bc281856020015187612baa906157ad565b8684600001818151612bd491906157ff565b915090600f0b9081600f0b8152505083606e60008b63ffffffff1663ffffffff16815260200190815260200160002060008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160010160008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b03160217905550505060408201518160020160008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b03160217905550505090505082606d60008b63ffffffff1663ffffffff16815260200190815260200160002060008a815260200190815260200160002060010160008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b031602179055509050506000606d60008b63ffffffff1663ffffffff16815260200190815260200160002060008a81526020019081526020016000206000016040518060200160405290816000820160009054906101000a9004600f0b600f0b600f0b8152505090506000606d60008063ffffffff1663ffffffff16815260200190815260200160002060008b81526020019081526020016000206000016040518060200160405290816000820160009054906101000a9004600f0b600f0b600f0b815250509050612e3c84838a61400e565b612e4783828961400e565b63ffffffff8b166000818152606d602090815260408083208e84528252808320865181546001600160801b03199081166001600160801b0392831617909255600080516020615c6283398151915284528285208751815490931692821692909217909155938352606c8252808320885189840151908616600160801b9187168202178255898301516060808c015191881691881683029190911760019390930192909255938052875192880151928516928516840292909217600080516020615c82833981519152558601519086015190831692160217600080516020615ca283398151915255505050505050935093915050565b612f44613da1565b63ffffffff83166000818152606c6020908152604080832081516080810183528154600f81810b8352600160801b91829004810b8387015260019093015480840b8386015204820b6060820152948452606d835281842087855283529281902081519283019091525490910b8152612fbd82828561400e565b63ffffffff85166000818152606d602090815260408083208884528252808320855181546001600160801b0319166001600160801b0391821617909155938352606c825291829020855191860151918416600160801b92851683021781559185015160608601519084169316029190911760019190910155610b74565b613042614cd8565b61304a614cff565b63ffffffff84166000818152606c6020908152604080832081516080810183528154600f81810b8352600160801b91829004810b8387015260019093015480840b8386015204820b6060820152948452606d835281842088855283529281902081519283019091525490910b8152816130c381836138a7565b9350935050505b9250929050565b6065546001600160a01b031633146130fb5760405162461bcd60e51b815260040161095190615507565b600081600f0b1215801561311b5750670de0b6b3a7640000600f82900b13155b6040518060400160405280600381526020016242504360e81b815250906131555760405162461bcd60e51b81526004016109519190615584565b5063ffffffff91909116600090815260716020526040902080546001600160801b0319166001600160801b03909216919091179055565b613194614d16565b610e6582613d88565b6131a5613902565b6001600160a01b03811661320a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610951565b6132138161395c565b50565b6000613220613da1565b60408051608081018252600080516020615c8283398151915254600f81810b8352600160801b91829004810b602084810191909152600080516020615ca28339815191525480830b8587015292909204810b60608401526000878152600080516020615c62833981519152835284812085519384019095529354900b815290916132aa83836138a7565b5190506000600f82900b12156132f35760006132d86132d1876132cc856157ad565b6149c4565b60006149e0565b90506132e481876157ff565b95506132f184848361400e565b505b506000808052606c60209081528351848201516001600160801b03918216600160801b918316820217600080516020615c828339815191525560408087015160609097015196831696831690910295909517600080516020615ca283398151915255968252600080516020615c62833981519152905291909120905181546001600160801b031916941693909317909255919050565b604080518082019091526002815261049560f41b602082015263ffffffff85166133c65760405162461bcd60e51b81526004016109519190615584565b506133cf613da1565b63ffffffff84166000818152606c602090815260408083208151608080820184528254600f81810b8452600160801b91829004810b8488015260019094015480850b84870152819004840b60608085019190915285519283018652600080516020615c828339815191525480860b8452829004850b83880152600080516020615ca28339815191525480860b8488015291909104840b90820152958552606d84528285208986528452828520835180860185529054830b8152898652600080516020615c6283398151915285529483902083519485019093529154900b82529291906134bc84838861400e565b6134c783828761400e565b63ffffffff88166000818152606d602090815260408083208b84528252808320865181546001600160801b03199081166001600160801b0392831617909255600080516020615c6283398151915284528285208751815490931692821692909217909155938352606c8252808320885189840151908616600160801b9187168202178255898301516060808c015191881691881683029190911760019390930192909255938052875192880151928516928516840292909217600080516020615c82833981519152558601519086015190831692160217600080516020615ca2833981519152555050505050505050565b600063ffffffff821615806135d357508163ffffffff166005145b806135e457508163ffffffff16601f145b806135f557508163ffffffff166029145b8061360657508163ffffffff16606d145b1561361a5750670de0b6b3a7640000919050565b8163ffffffff16600103613635575065246139ca8000919050565b8163ffffffff166003148061365057508163ffffffff16605b145b8061366157508163ffffffff16605d145b8061367257508163ffffffff16606f145b156136855750660221b262dd8000919050565b506000919050565b600054610100900460ff16158080156136ad5750600054600160ff909116105b806136c75750303b1580156136c7575060005460ff166001145b61372a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610951565b6000805460ff19166001179055801561374d576000805461ff0019166101001790555b6137556149f5565b61375e83614a24565b6137678261319d565b606680546001600160a01b0319166001600160a01b038781169182179092558482166000908152606a6020526040808220805460ff199081166001908117909255938352818320805485168217905593881682529020805490911690911790558015610b74576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610918565b7fb6ad4743e88e2c9f40d48e56287cc4f2c3013181bb128d12ca2114c48fe2926690565b600080670de0b6b3a7640000600f85810b9085900b025b05905060016001607f1b03198112801590613866575060016001607f1b038113155b6040518060400160405280600281526020016127a360f11b8152509061389f5760405162461bcd60e51b81526004016109519190615584565b509392505050565b6138af614cff565b6000808360000151600f0b13156138c8575082516138cf565b5060208301515b60408051808201909152835181906138ea90600f0b8461382d565b600f0b815260200182600f0b81525091505092915050565b6033546001600160a01b03163314610dde5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610951565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6139b6614d16565b63ffffffff831660009081526020838152604091829020825160a0810184529054600381810b808452600160201b8304820b94840194909452600160401b8204810b94830194909452600160601b810490930b6060820152600160801b909204600f0b6080830152613a2c90633b9aca0061566e565b600f0b82526020810151613a479060030b633b9aca0061566e565b600f0b60208301526040810151613a659060030b633b9aca0061566e565b600f0b60408301526060810151613a839060030b633b9aca0061566e565b600f90810b6060840152608091820151900b9082015292915050565b600080613aac8484610de0565b51946000945092505050565b60006002826002811115613ace57613ace614fc7565b03613ae25750670de0b6b3a76400006114cf565b60008084600f0b12613b1b576000836002811115613b0257613b02614fc7565b14613b11578460400151613b14565b84515b9050613b47565b6000836002811115613b2f57613b2f614fc7565b14613b3e578460600151613b44565b84602001515b90505b949350505050565b63ffffffff82166000908152606d602090815260408083208484528252808320815192830190915260010154600f0b808252829182918203613b9c57600080600093509350935050613c63565b63ffffffff8087166000908152606e6020908152604080832081516060810183528154600f90810b825283518085018552600184015480830b8252600160801b90819004830b82880152838701919091528451808601865260029094015480830b855204810b9483019490945291820152805185519194613c22939290920b91613ca616565b604083015151909150600090613c3b90600f0b8361382d565b602084015151909150600090613c5490600f0b8461382d565b91975090955060009450505050505b9250925092565b6000613c9b83600f0b613c898487600f0b61382d90919063ffffffff16565b600f0b613c969190615ad7565b614a4e565b613b4790600261566e565b600081600f0b600014156040518060400160405280600381526020016222212d60e91b81525090613cea5760405162461bcd60e51b81526004016109519190615584565b50600082600f0b670de0b6b3a7640000600f0b85600f0b02816138445761384461584f565b8051600f0b600003613d28579051600f0b602090910152565b6000808260000151600f0b1315613d4157508151613d48565b5060208201515b80600f0b8260200151600f0b03613d5e57505050565b60208201518251613d77919061113690600f0b8461382d565b600f90810b83520b60209091015250565b613d90614d16565b610e6582613d9c613809565b6139ae565b336000908152606a602090815260409182902054825180840190935260018352605560f81b9183019190915260ff166132135760405162461bcd60e51b81526004016109519190615584565b6000613e016065546001600160a01b031690565b6001600160a01b0316638f4f8ecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e629190615b8a565b905090565b8151600f0b158015613e7e57506020820151600f0b155b15613e9257670de0b6b3a764000060208301525b60008260000151600f0b1315613edc57613ec082602001518360000151600f0b613ca690919063ffffffff16565b83604001818151613ed191906157ff565b600f0b905250613f12565b613efa82602001518360000151600f0b613ca690919063ffffffff16565b83606001818151613f0b919061561d565b600f0b9052505b6000808360000151600f0b1315613f2b57508251613f32565b5060208301515b81613f5b613f50856020015184600f0b613ca690919063ffffffff16565b8551600f0b9061382d565b613f65919061561d565b600f0b80845260001215613f7b57508251613f82565b5060208301515b600f81810b602085015283516000910b1315613fd257613fb683602001518460000151600f0b613ca690919063ffffffff16565b84604001818151613fc7919061561d565b600f0b905250614008565b613ff083602001518460000151600f0b613ca690919063ffffffff16565b8460600181815161400191906157ff565b600f0b9052505b50505050565b60008260000151600f0b131561403c5781516040840180516140319083906157ff565b600f0b905250614056565b815160608401805161404f90839061561d565b600f0b9052505b614061838383614b0a565b60008260000151600f0b131561408f57815160408401805161408490839061561d565b600f0b905250505050565b81516060840180516140849083906157ff565b6000806140c384600001518560400151600f0b61382d90919063ffffffff16565b905060006140e585602001518660600151600f0b61382d90919063ffffffff16565b905060006140f7600f83900b84613ca6565b63ffffffff88166000908152606b60209081526040808320815160a08101835281546001600160a01b031681526001820154600f81810b95830195909552600160801b90819004850b93820184905260029092015480850b606083015291909104830b6080820152939450919084900b900361417557506000614211565b8160200151600f0b83600f0b12156141ba576141a98260200151611136858560600151600f0b61382d90919063ffffffff16565b6141b3908261561d565b9050614211565b6141f56141e78360200151670de0b6b3a76400006141d891906157ff565b602085015161113690876157ff565b6080840151600f0b9061382d565b8260600151614204919061561d565b61420e908261561d565b90505b61422c6142216301e13380614b81565b600f83900b90613ca6565b905061424d8761424483670de0b6b3a764000061561d565b600f0b90614bf1565b95505050600061426a670de0b6b3a764000086610fa991906157ff565b9050600061428b610fa96702c68af0bb140000670de0b6b3a76400006157ff565b905060006142a761429c83856157ff565b600f88900b9061382d565b60208a01519091506142bc90600f0b8861382d565b600f0b60208a015260006142d883670de0b6b3a764000061561d565b8a519091506142ea90600f0b8261382d565b600f90810b8b5282900b156143725763ffffffff8b166000908152606d6020908152604080832083805282529182902082519182019092529054600f0b81526143348b828561400e565b63ffffffff8c166000908152606d602090815260408083208380529091529020815181546001600160801b0319166001600160801b03909116179055505b63ffffffff8b16600090815260716020526040902054600f0b156144335760006143c46143a26301e13380614b81565b63ffffffff808f16600090815260716020526040902054600f0b9190613ca616565b905060006143de8b61424484670de0b6b3a764000061561d565b60208d01519091506143f390600f0b8261382d565b600f90810b60208e01528c5161440a910b8261382d565b600f90810b8d5261441e9084900b8261382d565b925061442e600f8b900b8261382d565b995050505b6040805163ffffffff8d1681526001600160801b038b166020820152600f83810b828401528a810b606083015284900b608082015290517f6ac06550b1d7756afb13ae15bdb7f009838eeb491868f6cea5664968b8ed71fd9181900360a00190a15050505050505050505050565b600082600f0b600014806144b8575081600f0b6000145b806144d0575060006144ca868561561d565b600f0b13155b806144e8575060006144e2858461561d565b600f0b13155b156144f557506000613b47565b600082600f0b84600f0b6145099190615ad7565b90506000614517868561561d565b600f0b614524888761561d565b600f0b6145319190615ad7565b919091139695505050505050565b6001600160a01b03851661455257600080fd5b806040015160030b816000015160030b1315801561457b5750633b9aca00816040015160030b13155b80156145955750806060015160030b816020015160030b12155b80156145ac5750633b9aca00816060015160030b12155b6040518060400160405280600381526020016242504360e81b815250906145e65760405162461bcd60e51b81526004016109519190615584565b50806145f0613809565b63ffffffff8981166000818152602093845260409081902085518154958701518784015160608901516080909901516001600160801b03908116600160801b02998816600160601b0263ffffffff60601b19928916600160401b0292909216600160401b600160801b0319938916600160201b026001600160401b0319909a16949098169390931797909717169490941794909417929092169390931790915560665490516343b16a1160e11b815260048101929092526001600160a01b031690638762d42290602401600060405180830381600087803b1580156146d457600080fd5b505af11580156146e8573d6000803e3d6000fd5b5050505060688790806001815401808255809150506001900390600052602060002090600891828204019190066004029091909190916101000a81548163ffffffff021916908363ffffffff1602179055506000600160688054905061474e9190615ba7565b90505b8015614911576068614764600183615ba7565b8154811061477457614774615551565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1663ffffffff16606882815481106147b3576147b3615551565b6000918252602090912060088204015460079091166004026101000a900463ffffffff1610156148fa576000606882815481106147f2576147f2615551565b6000918252602090912060088204015460079091166004026101000a900463ffffffff1690506068614825600184615ba7565b8154811061483557614835615551565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff166068838154811061486e5761486e615551565b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908363ffffffff1602179055508060686001846148b19190615ba7565b815481106148c1576148c1615551565b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908363ffffffff160217905550506148ff565b614911565b8061490981615bbe565b915050614751565b5061491a613ded565b6001600160a01b0316632da1c59b8888888888886040518763ffffffff1660e01b815260040161494f969594939291906159a1565b600060405180830381600087803b15801561496957600080fd5b505af115801561497d573d6000803e3d6000fd5b505060405163ffffffff8a1681527f3286b0394bf1350245290b7226c92ed186bd716f28938e62dbb895298f0181729250602001905060405180910390a150505050505050565b600081600f0b83600f0b126149d957816114cf565b5090919050565b600081600f0b83600f0b136149d957816114cf565b600054610100900460ff16614a1c5760405162461bcd60e51b815260040161095190615bd5565b610dde614c79565b614a2c613902565b606580546001600160a01b0319166001600160a01b0392909216919091179055565b600080821215614a9c5760405162461bcd60e51b815260206004820152601960248201527864732d6d6174682d737172742d6e6f6e2d706f73697469766560381b6044820152606401610951565b6003821315614afb5750806000614ab4600283615b5c565b614abf906001615c20565b90505b81811215614af557905080600281614ada8186615b5c565b614ae49190615c20565b614aee9190615b5c565b9050614ac2565b50919050565b8115614b05575060015b919050565b6000808360000151600f0b1315614b2357508251614b2a565b5060208301515b82516000908390614b3e90600f0b8461382d565b614b48919061561d565b9050600081600f0b1315614b5f5784519150614b67565b846020015191505b614b75600f82900b83613ca6565b600f0b90935250505050565b6000600f82900b670de0b6b3a76400000260016001607f1b03198112801590614bb1575060016001607f1b038113155b6040518060400160405280600281526020016127a360f11b81525090614bea5760405162461bcd60e51b81526004016109519190615584565b5092915050565b60008082600f0b12156040518060400160405280600281526020016127a360f11b81525090614c335760405162461bcd60e51b81526004016109519190615584565b50670de0b6b3a764000060015b83600f0b81600f0b1361389f57808416600f0b15614c6557614c62828661382d565b91505b614c6f858661382d565b9450600202614c40565b600054610100900460ff16614ca05760405162461bcd60e51b815260040161095190615bd5565b610dde3361395c565b60405180606001604052806000600f0b8152602001614cc6614cff565b8152602001614cd3614cff565b905290565b60408051608081018252600080825260208201819052918101829052606081019190915290565b604080518082019091526000808252602082015290565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b63ffffffff8116811461321357600080fd5b600060208284031215614d6857600080fd5b81356114cf81614d44565b6001600160a01b038116811461321357600080fd5b600080600080600060a08688031215614da057600080fd5b8535614dab81614d73565b94506020860135614dbb81614d73565b93506040860135614dcb81614d73565b92506060860135614ddb81614d73565b91506080860135614deb81614d73565b809150509295509295909350565b80600f0b811461321357600080fd5b60008060408385031215614e1b57600080fd5b8235614e2681614d44565b91506020830135614e3681614df9565b809150509250929050565b60008083601f840112614e5357600080fd5b5081356001600160401b03811115614e6a57600080fd5b6020830191508360208260051b85010111156130ca57600080fd5b60008060008060408587031215614e9b57600080fd5b84356001600160401b0380821115614eb257600080fd5b614ebe88838901614e41565b90965094506020870135915080821115614ed757600080fd5b50614ee487828801614e41565b95989497509550505050565b60008060408385031215614f0357600080fd5b8235614f0e81614d44565b946020939093013593505050565b8051600f0b82526020810151600f0b60208301525050565b8051600f0b82526020810151600f0b60208301526040810151600f0b60408301526060810151600f0b60608301525050565b8451600f0b8152602080860151610180830191614f8590840182614f1c565b506040860151614f986060840182614f1c565b508451600f0b60a0830152614fb060c0830185614f34565b614fbe610140830184614f1c565b95945050505050565b634e487b7160e01b600052602160045260246000fd5b6020810160028310614fff57634e487b7160e01b600052602160045260246000fd5b91905290565b6020808252825182820181905260009190848201906040850190845b8181101561504357835163ffffffff1683529284019291840191600101615021565b50909695505050505050565b60408101610e658284614f1c565b803560038110614b0557600080fd5b6000806040838503121561507f57600080fd5b8235915061508f6020840161505d565b90509250929050565b6000602082840312156150aa57600080fd5b5035919050565b6000806000606084860312156150c657600080fd5b8335925060208401356150d881614d44565b91506150e66040850161505d565b90509250925092565b600080600080600060a0868803121561510757600080fd5b853561511281614d44565b945060208601359350604086013561512981614df9565b9250606086013561513981614df9565b91506080860135614deb81614df9565b60006020828403121561515b57600080fd5b81356001600160801b03811681146114cf57600080fd5b6000806040838503121561518557600080fd5b50508035926020909101359150565b60405160a081016001600160401b03811182821017156151c457634e487b7160e01b600052604160045260246000fd5b60405290565b60405160c081016001600160401b03811182821017156151c457634e487b7160e01b600052604160045260246000fd5b8035600381900b8114614b0557600080fd5b600060a0828403121561521e57600080fd5b615226615194565b9050615231826151fa565b815261523f602083016151fa565b6020820152615250604083016151fa565b6040820152615261606083016151fa565b6060820152608082013561527481614df9565b608082015292915050565b60008060c0838503121561529257600080fd5b823561529d81614d44565b915061508f846020850161520c565b6000806000606084860312156152c157600080fd5b83356152cc81614d44565b925060208401356152dc81614df9565b915060408401356152ec81614df9565b809150509250925092565b6000806020838503121561530a57600080fd5b82356001600160401b038082111561532157600080fd5b818501915085601f83011261533557600080fd5b81358181111561534457600080fd5b86602082850101111561535657600080fd5b60209290920196919550909350505050565b600060a08284031215614af557600080fd5b600080600080600080600080610200898b03121561539757600080fd5b88356153a281614d44565b975060208901356153b281614d44565b965060408901356153c281614d73565b955060608901356153d281614df9565b945060808901356153e281614df9565b935060a08901356153f281614df9565b92506154018a60c08b01615368565b91506154118a6101608b01615368565b90509295985092959890939650565b60008060006060848603121561543557600080fd5b833561544081614d44565b92506020840135915060408401356152ec81614df9565b60c081016154658285614f34565b6114cf6080830184614f1c565b60006020828403121561548457600080fd5b81356114cf81614d73565b600080604083850312156154a257600080fd5b823591506020830135614e3681614df9565b600080600080608085870312156154ca57600080fd5b84356154d581614d44565b93506020850135925060408501356154ec81614df9565b915060608501356154fc81614df9565b939692955090935050565b6020808252602a908201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686040820152691948195b991c1bda5b9d60b21b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561557957600080fd5b81356114cf81614df9565b600060208083528351808285015260005b818110156155b157858101830151858201604001528201615595565b818111156155c3576000604083870101525b50601f01601f1916929092016040019392505050565b634e487b7160e01b600052601160045260246000fd5b60006001600160801b038281166002600160801b03198101615613576156136155d9565b6001019392505050565b6000600f82810b9084900b828212801560016001607f1b0384900383131615615648576156486155d9565b60016001607f1b03198390038212811615615665576156656155d9565b50019392505050565b6000600f82810b9084900b60016001607f1b038382138484138082168484048611161561569d5761569d6155d9565b60016001607f1b031960008512828116878305871216156156c0576156c06155d9565b600087129250858205871284841616156156dc576156dc6155d9565b858505871281841616156156f2576156f26155d9565b5050509290910295945050505050565b600063ffffffff808316818103615613576156136155d9565b60006080828403121561572d57600080fd5b604051608081018181106001600160401b038211171561575d57634e487b7160e01b600052604160045260246000fd5b604052825161576b81614d44565b8152602083015161577b81614df9565b6020820152604083015161578e81614df9565b604082015260608301516157a181614df9565b60608201529392505050565b6000600f82900b6001607f1b81016157c7576157c76155d9565b60000392915050565b60006001600160401b03808316818516818304811182151516156157f6576157f66155d9565b02949350505050565b6000600f82810b9084900b828112801560016001607f1b031983018412161561582a5761582a6155d9565b60016001607f1b0382018313811615615845576158456155d9565b5090039392505050565b634e487b7160e01b600052601260045260246000fd5b600081600f0b83600f0b8061587c5761587c61584f565b60016001607f1b031982146000198214161561589a5761589a6155d9565b90059392505050565b60008183036101c08112156158b757600080fd5b6158bf6151ca565b83356158ca81614d44565b815260208401356158da81614df9565b602082015260408401356158ed81614df9565b6040820152606084013561590081614df9565b606082015260a0607f198301121561591757600080fd5b61591f615194565b9150608084013561592f81614d73565b825260a084013561593f81614df9565b602083015260c084013561595281614df9565b604083015260e084013561596581614df9565b606083015261010084013561597981614df9565b8060808401525081608082015261599485610120860161520c565b60a0820152949350505050565b63ffffffff96871681529490951660208501526001600160a01b03929092166040840152600f90810b606084015290810b60808301529190910b60a082015260c00190565b600060a082840312156159f857600080fd5b6114cf838361520c565b80546001600160801b0319166001600160801b0392909216919091179055565b80546001600160801b031660809290921b6001600160801b031916919091179055565b8135615a5081614d73565b81546001600160a01b0319166001600160a01b0391909116178155600181016020830135615a7d81614df9565b615a878183615a02565b506040830135615a9681614df9565b615aa08183615a22565b5050600281016060830135615ab481614df9565b615abe8183615a02565b506080830135615acd81614df9565b6140088183615a22565b60006001600160ff1b0381841382841380821686840486111615615afd57615afd6155d9565b600160ff1b6000871282811687830589121615615b1c57615b1c6155d9565b60008712925087820587128484161615615b3857615b386155d9565b87850587128184161615615b4e57615b4e6155d9565b505050929093029392505050565b600082615b6b57615b6b61584f565b600160ff1b821460001984141615615b8557615b856155d9565b500590565b600060208284031215615b9c57600080fd5b81516114cf81614d73565b600082821015615bb957615bb96155d9565b500390565b600081615bcd57615bcd6155d9565b506000190190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600080821280156001600160ff1b0384900385131615615c4257615c426155d9565b600160ff1b8390038412811615615c5b57615c5b6155d9565b5050019056feda90043ba5b4096ba14704bc227ab0d3167da15b887e62ab2e76e37daa7113567febd347df14ea35c529e50fb2dd629d4a6226f5ccc893710fb466f8b83823fc7febd347df14ea35c529e50fb2dd629d4a6226f5ccc893710fb466f8b83823fda26469706673582212205279aacced1dc7ea5d493c412e6e4fb5665edd3ea4fdee4ece80efdf59782f2d64736f6c634300080d0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101b15760003560e01c8063aed8e967116100f5578063aed8e96714610397578063b1cb0f42146103a8578063b8d80d8b146103b9578063c362d19e146103cc578063c55607b5146103f7578063c7167cf51461040a578063c9fe9ac314610437578063d386c1e81461044a578063d98752ec1461045d578063e0b0621f14610470578063e334be3314610483578063e343738c146104a4578063ec6271d2146105a0578063ecd9cba8146105b3578063f2fde38b14610617578063f39eeb101461062a578063f8a42e511461063d578063fdf4a0c01461065057600080fd5b8063130ea373146101b65780631459457a146101f7578063153ca6c01461020c57806330972b501461021f5780633d5cc9dc1461023257806345be7ed6146102555780634604d19b1461029c57806347428e7b146102ab5780634ac8d8c1146102c0578063715018a6146102d35780637c1e1487146102db578063871d0912146102fb5780638936f7cd1461030e5780638a1d43c9146103215780638da5cb5b1461036057806398de72fe14610371578063ad733b8e14610384575b600080fd5b6101df6101c4366004614d56565b63ffffffff16600090815260716020526040902054600f0b90565b604051600f9190910b81526020015b60405180910390f35b61020a610205366004614d88565b610663565b005b61020a61021a366004614e08565b610927565b61020a61022d366004614e85565b61099a565b610245610240366004614ef0565b610b7b565b6040516101ee9493929190614f66565b610284610263366004614d56565b63ffffffff166000908152606b60205260409020546001600160a01b031690565b6040516001600160a01b0390911681526020016101ee565b60006040516101ee9190614fdd565b6102b3610cb1565b6040516101ee9190615005565b61020a6102ce366004614d56565b610d35565b61020a610dcc565b6102ee6102e9366004614ef0565b610de0565b6040516101ee919061504f565b6101df61030936600461506c565b610e6b565b61020a61031c366004615098565b610fed565b61033461032f3660046150b1565b611461565b604080518251600f90810b8252602080850151820b908301529282015190920b908201526060016101ee565b6033546001600160a01b0316610284565b61020a61037f3660046150ef565b6114d6565b61020a610392366004615149565b611a6c565b6065546001600160a01b0316610284565b6066546001600160a01b0316610284565b6101df6103c7366004615172565b611d0c565b6070546103df906001600160401b031681565b6040516001600160401b0390911681526020016101ee565b61020a61040536600461527f565b611f5d565b61041d6104183660046152ac565b612075565b60408051600f93840b81529190920b6020820152016101ee565b61020a6104453660046152f7565b6122f5565b61020a61045836600461537a565b612627565b61041d61046b366004615420565b612938565b61020a61047e366004615420565b612f3c565b610496610491366004614ef0565b61303a565b6040516101ee929190615457565b61054a6104b2366004614d56565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091525063ffffffff166000908152606b6020908152604091829020825160a08101845281546001600160a01b031681526001820154600f81810b94830194909452600160801b90819004840b9482019490945260029091015480830b606083015292909204900b608082015290565b6040516101ee9190600060a08201905060018060a01b0383511682526020830151600f0b60208301526040830151600f0b60408301526060830151600f0b60608301526080830151600f0b608083015292915050565b61020a6105ae366004614e08565b6130d1565b6105c66105c1366004614d56565b61318c565b6040516101ee9190600060a0820190508251600f0b82526020830151600f0b60208301526040830151600f0b60408301526060830151600f0b60608301526080830151600f0b608083015292915050565b61020a610625366004615472565b61319d565b6101df61063836600461548f565b613216565b61020a61064b3660046154b4565b613389565b6101df61065e366004614d56565b6135b8565b61066f8585848461368d565b6040805160a080820183526001600160a01b038681168352670b1a2bc2ec5000006020808501918252662386f26fc10000858701908152668e1bc9bf0400006060808801918252670de0b6b3a76400006080808a0182815260008052606b875299517fc8cc8bda7ad4886bea3ebbdafa02e79d37c39bf4011696b26a31a0802fd9458b80546001600160a01b0319169190991617909755945192516001600160801b03938416600160801b9185168202177fc8cc8bda7ad4886bea3ebbdafa02e79d37c39bf4011696b26a31a0802fd9458c55915197519783169790921602959095177fc8cc8bda7ad4886bea3ebbdafa02e79d37c39bf4011696b26a31a0802fd9458d5585519384018652633b9aca0080855290840181905294830185905292820193909352918201526107a2613809565b6000808052602091825260408082208451815486860151878501516060808a015160809a8b01516001600160801b03908116600160801b90810263ffffffff938416600160601b0263ffffffff60601b19968516600160401b0296909616600160401b600160801b0319978516600160201b026001600160401b0319909916998516999099179790971795909516969096179290921785169390931790945584519788018552670de0b6b3a7640000808952888801908152888601878152928901878152878052606c8952985190518416820290841617600080516020615c828339815191525590519651821602951694909417600080516020615ca28339815191525560688054600181018255908352600881047fa2153420d844928b4421650203c77babc8b33d7f2e7b450e2966db0c2209775301805460079092166004026101000a909502191690935591519182527f3286b0394bf1350245290b7226c92ed186bd716f28938e62dbb895298f01817291015b60405180910390a15050505050565b6065546001600160a01b0316331461095a5760405162461bcd60e51b815260040161095190615507565b60405180910390fd5b80610963613809565b63ffffffff9093166000908152602093909352604090922080546001600160801b03938416600160801b0293169290921790915550565b60005b6001600160801b038116841115610b745760006068826001600160801b0316815481106109cc576109cc615551565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff16808352606c825260409283902083516080810185528154600f81810b8352600160801b91829004810b9583019590955260019092015480850b95820195909552930490910b6060830152915086866001600160801b038516818110610a5857610a58615551565b9050602002016020810190610a6d9190615567565b600f0b610a8e82600001518360400151600f0b61382d90919063ffffffff16565b600f0b14604051806040016040528060058152602001644453594e4360d81b81525090610ace5760405162461bcd60e51b81526004016109519190615584565b508484846001600160801b0316818110610aea57610aea615551565b9050602002016020810190610aff9190615567565b600f0b610b2082602001518360600151600f0b61382d90919063ffffffff16565b600f0b14604051806040016040528060058152602001644453594e4360d81b81525090610b605760405162461bcd60e51b81526004016109519190615584565b50505080610b6d906155ef565b905061099d565b5050505050565b610b83614ca9565b604080516020810190915260008152610b9a614cd8565b610ba2614cff565b63ffffffff86166000818152606e602090815260408083208151606080820184528254600f90810b83528451808601865260018086015480840b8352600160801b90819004840b838a0152858901929092528651808801885260029096015480840b8752829004830b8689015284870195909552888852606c87528588208651608081018852815480850b8252839004840b818a01529086015480840b8289015291909104820b81840152978752606d86528487208d8852865295849020845191820185528054870b828601908152825284518087019095529092015490940b82529182018190528151929392848285610c9c81856138a7565b929e919d509b50909950975050505050505050565b60606068805480602002602001604051908101604052809291908181526020018280548015610d2b57602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411610cee5790505b5050505050905090565b6000610d4282600161303a565b5090506000610d6582600001518360400151600f0b61382d90919063ffffffff16565b90506000610d8783602001518460600151600f0b61382d90919063ffffffff16565b905080600f0b82600f0b1215604051806040016040528060028152602001614d5560f01b81525090610b745760405162461bcd60e51b81526004016109519190615584565b610dd4613902565b610dde600061395c565b565b610de8614cff565b63ffffffff83166000818152606c6020908152604080832081516080810183528154600f81810b8352600160801b91829004810b8387015260019093015480840b8386015204820b6060820152948452606d835281842087855283529281902081519283019091525490910b8152610e6082826138a7565b925050505b92915050565b600080610e76610cb1565b90506000610e82613809565b905060005b82518163ffffffff161015610fe4576000838263ffffffff1681518110610eb057610eb0615551565b602002602001015190506000610ec682856139ae565b9050600080610ed5848b613a9f565b915091506000610ee684848c613ab8565b9050610ef2828a61561d565b985082600f0b600014610f6357610f12670de0b6b3a7640000600261566e565b600f0b81600f0b03610f365760016001607f1b031998505050505050505050610e65565b6080840151610f5690610f4d600f86900b8461382d565b600f0b9061382d565b610f60908a61561d565b98505b5050506000806000610f75858c613b4f565b92509250925082600f0b600014610fcc576000610f9784848760800151613c6a565b905081610fb4610fa98760018f613ab8565b600f84900b9061382d565b610fbe919061561d565b610fc8908b61561d565b9950505b50505050508080610fdc90615702565b915050610e87565b50505092915050565b6066546040805180820190915260018152605560f81b6020820152906001600160a01b031633146110315760405162461bcd60e51b81526004016109519190615584565b50600061103c610cb1565b905060005b8151816001600160801b0316101561145c57600082826001600160801b03168151811061107057611070615551565b60209081029190910181015163ffffffff81166000818152606c8452604080822081516080810183528154600f81810b8352600160801b91829004810b838a015260019093015480840b8386015204820b6060820152938352606d86528183208a8452865281832082519687019092529054900b8452919350916110f59083906138a7565b905060008160000151600f0b1215611448578151604083015160009161111e91600f0b9061382d565b6040840151835191925061113f91611136908461561d565b600f0b90613ca6565b600f0b80845260001261115157600080fd5b61116f83602001518360000151600f0b613ca690919063ffffffff16565b83606001818151611180919061561d565b600f0b90525063ffffffff84166000818152606d602090815260408083208b8452909152902080546001600160801b03191690556113085760005b86518163ffffffff161015611302576000878263ffffffff16815181106111e4576111e4615551565b60200260200101519050600063ffffffff168163ffffffff160361120857506112f2565b63ffffffff81166000908152606e602090815260409182902082516060810184528154600f90810b825284518086018652600184015480830b8252600160801b90819004830b828701528386019182528651808801885260029095015480840b86520490910b938301939093529283015251611285908790613d0f565b63ffffffff82166000908152606e6020908152604091829020835181546001600160801b0319166001600160801b0391821617825584830151805190840151908216600160801b918316820217600184015593850151805193015192811692169092021760029091015550505b6112fb81615702565b90506111bb565b506113f7565b63ffffffff84166000908152606e602090815260409182902082516060810184528154600f90810b825284518086018652600184015480830b8252600160801b90819004830b82870152838601919091528551808701875260029094015480830b855204900b9282019290925291810182905290611387908590613d0f565b63ffffffff85166000908152606e6020908152604091829020835181546001600160801b039182166001600160801b0319909116178255848301518051908401518216600160801b9081029183169190911760018401559490930151805192015183169093029116176002909101555b63ffffffff84166000908152606c60209081526040918290208551918601516001600160801b03928316600160801b9184168202178255928601516060870151908316921690920217600190910155505b50505080611455906155ef565b9050611041565b505050565b604080516060810182526000808252602082018190529181018290529061148784613d88565b905060006114958587613a9f565b509050604051806060016040528082600f0b81526020018360800151600f0b81526020016114c584600188613ab8565b600f0b9052925050505b9392505050565b6114de613da1565b600083600f0b1380156114f45750600082600f0b135b80156115035750600081600f0b135b60405180604001604052806003815260200162494c4160e81b8152509061153d5760405162461bcd60e51b81526004016109519190615584565b506000611548613ded565b604051631d029b4d60e01b815263ffffffff881660048201526001600160a01b039190911690631d029b4d90602401608060405180830381865afa158015611594573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b8919061571b565b6000015163ffffffff161460405180604001604052806002815260200161049560f41b815250906115fc5760405162461bcd60e51b81526004016109519190615584565b5063ffffffff85166000818152606e602090815260408083208151606080820184528254600f90810b83528451808601865260018086015480840b8352600160801b90819004840b838a0152858901929092528651808801885260029096015480840b8752829004830b86890152848701958652988852606c808852868920875160808082018a52825480870b8352859004860b828c015291909b015480850b8c8a0152839004840b8b86015289805290885286519081018752600080516020615c828339815191525480840b8252829004830b97810197909752600080516020615ca28339815191525480830b96880196909652909404840b90850152905151909493910b156117345760408401515160208501515161172f9161172491600f0b90613ca6565b600f89900b9061382d565b61174f565b61174f6117408a613d88565b60800151600f89900b9061382d565b905085600f0b81600f0b1215604051806040016040528060038152602001620a6a8960eb1b815250906117955760405162461bcd60e51b81526004016109519190615584565b5084600f0b81600f0b1315604051806040016040528060038152602001620a6a8960eb1b815250906117da5760405162461bcd60e51b81526004016109519190615584565b508351600090600f0b81036117fa576117f3828961561d565b9050611819565b84516040860151516118169190610f4d90600f8c900b90613ca6565b90505b6118288486604001518a613e67565b61183783866020015184613e67565b8085600001818151611849919061561d565b600f90810b90915263ffffffff8c166000908152606d602090815260408083208e84529091528120600101805485945090926118879185910b61561d565b82546101009290920a6001600160801b0381810219909316918316021790915563ffffffff8c166000908152606e602090815260408083208a5181546001600160801b0319169086161781558a830151805190840151908616600160801b91871682021760018301558b83015180519085015190871696160294909417600290940193909355606d81528282208d83528152828220835180830185529054600f90810b82528e8452600080516020615c628339815191528352928490208451928301909452925490910b815290915061196986836119648d6157ad565b61400e565b6119778582611964876157ad565b63ffffffff909b166000818152606d602090815260408083208e84528252808320945185546001600160801b039182166001600160801b0319918216179096559d8352600080516020615c6283398151915282528083209e518f54908f16951694909417909d55908152606c8c528181208651878e01518d16600160801b908102918e16919091178255878401516060988901518e168202908e16176001929092019190915590805284519b8501518b1681029b8b169b909b17600080516020615c828339815191525583015192909301518816909802961695909517600080516020615ca283398151915255505050505050565b6065546001600160a01b03163314611a965760405162461bcd60e51b815260040161095190615507565b611a9e614cd8565b611aac6201518060076157d0565b6001600160401b0316826001600160801b0316106040518060400160405280600381526020016249544960e81b81525090611afa5760405162461bcd60e51b81526004016109519190615584565b5060005b60685463ffffffff8216101561145c57600060688263ffffffff1681548110611b2957611b29615551565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff16808352606c825260409283902083516080810185528154600f81810b8352600160801b91829004810b9583019590955260019092015480850b95820195909552930490910b6060830152915081611ba3578093505b8060400151600f0b600003611bb9575050611cfa565b63ffffffff82166000908152606e602090815260409182902082516060810184528154600f90810b825284518086018652600184015480830b8252600160801b90819004830b82870152838601919091528551808701875260029094015480830b855204900b9282019290925291810191909152611c388383886140a2565b611c46828260400151613d0f565b611c54858260200151613d0f565b63ffffffff83166000908152606e60209081526040808320845181546001600160801b0319166001600160801b0391821617825585840151805190850151908216600160801b91831682021760018085019190915587850151805190870151908416908416830217600290940193909355606c85529483902087519488015194821694821686029490941784559186015160608701519083169216909302179101555050505b80611d0481615702565b915050611afe565b600080611d17610cb1565b905060005b8151816001600160801b03161015611f5557600082826001600160801b031681518110611d4b57611d4b615551565b602002602001015190506000611d69828860016001607f1b03612938565b91505080600f0b600014611f42576000611dae6032611d92611d8a86613d88565b856001613ab8565b611da490670de0b6b3a76400006157ff565b610fa99190615865565b90506000611dc8600f83900b6706f05b59d3b2000061382d565b9050611dd481836157ff565b9150611de0818861561d565b60408051608081018252600080516020615c8283398151915254600f81810b8352600160801b91829004810b602084810191909152600080516020615ca28339815191525480830b8587015292909204810b606084015260008e8152600080516020615c62833981519152808452858220865180860188529054840b81528f83529084529085902085519384019095529354900b815292995091611e93838386611e89896157ad565b61196491906157ff565b611e9e83828761400e565b60008c8152600080516020615c6283398151915260209081526040808320945185546001600160801b039182166001600160801b0319918216179096558e845281842094518554908216961695909517909355908052606c81528351908401518316600160801b90810291841691909117600080516020615c828339815191525590830151606090930151821602911617600080516020615ca28339815191525550505b505080611f4e906155ef565b9050611d1c565b505092915050565b611f65613902565b806040015160030b816000015160030b13158015611f915750806060015160030b816020015160030b12155b6040518060400160405280600381526020016242504360e81b81525090611fcb5760405162461bcd60e51b81526004016109519190615584565b5080611fd5613809565b63ffffffff9384166000908152602091825260409081902083518154938501519285015160608601516080909601516001600160801b03908116600160801b02968916600160601b0263ffffffff60601b19928a16600160401b0292909216600160401b600160801b0319958a16600160201b026001600160401b0319909716939099169290921794909417929092169590951791909117161790915550565b600080612080613da1565b63ffffffff85166000908152606e602090815260409182902082516060810184528154600f90810b825284518086018652600184015480830b8252600160801b90819004830b828701528386019182528651808801885260029095015480840b86520490910b93830193909352928301819052519051516121059187918791906144a1565b60405180604001604052806002815260200161494d60f01b8152509061213e5760405162461bcd60e51b81526004016109519190615584565b5063ffffffff86166000908152606c602052604080822054918052600080516020615c8283398151915254908301518051600f93840b939290920b9188919061218890839061561d565b600f0b905250602083015180518791906121a390839061561d565b600f90810b90915263ffffffff8a81166000908152606e6020908152604091829020885181546001600160801b0319166001600160801b0391821617825589830151805190840151908216600160801b9183168202176001840155938a0151805193015192811692169092021760029091015561222892509089900b908490613ca616565b63ffffffff89166000908152606c602052604081206001018054909190612253908490600f0b61561d565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055506122908187600f0b613ca690919063ffffffff16565b6000808052606c602052600080516020615ca283398151915280549091906122bc908490600f0b61561d565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508686945094505050505b935093915050565b6065546001600160a01b0316331461231f5760405162461bcd60e51b815260040161095190615507565b600061232d828401846158a3565b60a081015181519192509063ffffffff16156125a557806040015160030b816000015160030b1315801561236f5750806060015160030b816020015160030b12155b80156123a25750608082015151825163ffffffff166000908152606b60205260409020546001600160a01b039081169116145b6040518060400160405280600381526020016242504360e81b815250906123dc5760405162461bcd60e51b81526004016109519190615584565b5060006123e7613809565b835163ffffffff1660009081526020918252604090819020815160a0810183529054600381810b8352600160201b8204810b838601908152600160401b8304820b848601908152600160601b8404830b6060808701918252600160801b909504600f0b60808701528951840b865296890151830b90915293870151810b90935285015190910b90915290508061247b613809565b845163ffffffff9081166000908152602092835260409081902084518154948601519286015160608701516080909701516001600160801b03908116600160801b02978616600160601b0263ffffffff60601b19928716600160401b0292909216600160401b600160801b0319958716600160201b026001600160401b031990981693909616929092179590951792909216929092179290921791909116919091179055612527613ded565b6001600160a01b0316632da1c59b846000015163ffffffff60008760200151886040015189606001516040518763ffffffff1660e01b8152600401612571969594939291906159a1565b600060405180830381600087803b15801561258b57600080fd5b505af115801561259f573d6000803e3d6000fd5b50505050505b50608081810151915163ffffffff166000908152606b6020908152604091829020845181546001600160a01b0319166001600160a01b0390911617815590840151918401516001600160801b03928316600160801b91841682021760018301556060850151949093015193821693909116909102919091176002909101555050565b61262f613902565b63ffffffff881661263f57600080fd5b61265c888888888888612657368990038901896159e6565b61453f565b63ffffffff88166000908152606b60205260409020829061267d8282615a45565b9050506040518060800160405280670de0b6b3a7640000600f0b8152602001670de0b6b3a7640000600f0b81526020016000600f0b81526020016000600f0b815250606c60008a63ffffffff1663ffffffff16815260200190815260200160002060008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060408201518160010160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060608201518160010160106101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555090505060405180606001604052806000600f0b815260200160405180604001604052806000600f0b8152602001670de0b6b3a7640000600f0b815250815260200160405180604001604052806000600f0b8152602001670de0b6b3a7640000600f0b815250815250606e60008a63ffffffff1663ffffffff16815260200190815260200160002060008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160010160008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b03160217905550505060408201518160020160008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555050509050505050505050505050565b600080612943613da1565b600083600f0b1360405180604001604052806003815260200162494c4160e81b815250906129845760405162461bcd60e51b81526004016109519190615584565b5063ffffffff85166000818152606e602090815260408083208151606080820184528254600f90810b83528451808601865260018086015480840b8352600160801b90819004840b838a0152858901929092528651808801885260029096015480840b8752829004830b8689015284870195909552888852606d87528588208d895287528588208651808901885290860154830b8152988852606c808852868920875160808082018a52825480870b8352859004860b828c0152919097015480850b888a0152839004840b87860152988052875285519788018652600080516020615c828339815191525480830b8952819004820b96880196909652600080516020615ca28339815191525480820b9588019590955294909304840b92850192909252909392909187900b60026001607f1b031901612ac257825196505b86600f0b600003612add5760008095509550505050506122ed565b86600f0b8360000151600f0b1215604051806040016040528060038152602001620494c560ec1b81525090612b255760405162461bcd60e51b81526004016109519190615584565b508683600001818151612b3891906157ff565b600f90810b909152855160408701515190820b9250612b5d9190810b908a900b615ad7565b612b679190615b5c565b95508360000151600f0b846020015160000151600f0b88600f0b612b8b9190615ad7565b612b959190615b5c565b9450612baf82856040015188612baa906157ad565b613e67565b612bc281856020015187612baa906157ad565b8684600001818151612bd491906157ff565b915090600f0b9081600f0b8152505083606e60008b63ffffffff1663ffffffff16815260200190815260200160002060008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160010160008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b03160217905550505060408201518160020160008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b03160217905550505090505082606d60008b63ffffffff1663ffffffff16815260200190815260200160002060008a815260200190815260200160002060010160008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b031602179055509050506000606d60008b63ffffffff1663ffffffff16815260200190815260200160002060008a81526020019081526020016000206000016040518060200160405290816000820160009054906101000a9004600f0b600f0b600f0b8152505090506000606d60008063ffffffff1663ffffffff16815260200190815260200160002060008b81526020019081526020016000206000016040518060200160405290816000820160009054906101000a9004600f0b600f0b600f0b815250509050612e3c84838a61400e565b612e4783828961400e565b63ffffffff8b166000818152606d602090815260408083208e84528252808320865181546001600160801b03199081166001600160801b0392831617909255600080516020615c6283398151915284528285208751815490931692821692909217909155938352606c8252808320885189840151908616600160801b9187168202178255898301516060808c015191881691881683029190911760019390930192909255938052875192880151928516928516840292909217600080516020615c82833981519152558601519086015190831692160217600080516020615ca283398151915255505050505050935093915050565b612f44613da1565b63ffffffff83166000818152606c6020908152604080832081516080810183528154600f81810b8352600160801b91829004810b8387015260019093015480840b8386015204820b6060820152948452606d835281842087855283529281902081519283019091525490910b8152612fbd82828561400e565b63ffffffff85166000818152606d602090815260408083208884528252808320855181546001600160801b0319166001600160801b0391821617909155938352606c825291829020855191860151918416600160801b92851683021781559185015160608601519084169316029190911760019190910155610b74565b613042614cd8565b61304a614cff565b63ffffffff84166000818152606c6020908152604080832081516080810183528154600f81810b8352600160801b91829004810b8387015260019093015480840b8386015204820b6060820152948452606d835281842088855283529281902081519283019091525490910b8152816130c381836138a7565b9350935050505b9250929050565b6065546001600160a01b031633146130fb5760405162461bcd60e51b815260040161095190615507565b600081600f0b1215801561311b5750670de0b6b3a7640000600f82900b13155b6040518060400160405280600381526020016242504360e81b815250906131555760405162461bcd60e51b81526004016109519190615584565b5063ffffffff91909116600090815260716020526040902080546001600160801b0319166001600160801b03909216919091179055565b613194614d16565b610e6582613d88565b6131a5613902565b6001600160a01b03811661320a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610951565b6132138161395c565b50565b6000613220613da1565b60408051608081018252600080516020615c8283398151915254600f81810b8352600160801b91829004810b602084810191909152600080516020615ca28339815191525480830b8587015292909204810b60608401526000878152600080516020615c62833981519152835284812085519384019095529354900b815290916132aa83836138a7565b5190506000600f82900b12156132f35760006132d86132d1876132cc856157ad565b6149c4565b60006149e0565b90506132e481876157ff565b95506132f184848361400e565b505b506000808052606c60209081528351848201516001600160801b03918216600160801b918316820217600080516020615c828339815191525560408087015160609097015196831696831690910295909517600080516020615ca283398151915255968252600080516020615c62833981519152905291909120905181546001600160801b031916941693909317909255919050565b604080518082019091526002815261049560f41b602082015263ffffffff85166133c65760405162461bcd60e51b81526004016109519190615584565b506133cf613da1565b63ffffffff84166000818152606c602090815260408083208151608080820184528254600f81810b8452600160801b91829004810b8488015260019094015480850b84870152819004840b60608085019190915285519283018652600080516020615c828339815191525480860b8452829004850b83880152600080516020615ca28339815191525480860b8488015291909104840b90820152958552606d84528285208986528452828520835180860185529054830b8152898652600080516020615c6283398151915285529483902083519485019093529154900b82529291906134bc84838861400e565b6134c783828761400e565b63ffffffff88166000818152606d602090815260408083208b84528252808320865181546001600160801b03199081166001600160801b0392831617909255600080516020615c6283398151915284528285208751815490931692821692909217909155938352606c8252808320885189840151908616600160801b9187168202178255898301516060808c015191881691881683029190911760019390930192909255938052875192880151928516928516840292909217600080516020615c82833981519152558601519086015190831692160217600080516020615ca2833981519152555050505050505050565b600063ffffffff821615806135d357508163ffffffff166005145b806135e457508163ffffffff16601f145b806135f557508163ffffffff166029145b8061360657508163ffffffff16606d145b1561361a5750670de0b6b3a7640000919050565b8163ffffffff16600103613635575065246139ca8000919050565b8163ffffffff166003148061365057508163ffffffff16605b145b8061366157508163ffffffff16605d145b8061367257508163ffffffff16606f145b156136855750660221b262dd8000919050565b506000919050565b600054610100900460ff16158080156136ad5750600054600160ff909116105b806136c75750303b1580156136c7575060005460ff166001145b61372a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610951565b6000805460ff19166001179055801561374d576000805461ff0019166101001790555b6137556149f5565b61375e83614a24565b6137678261319d565b606680546001600160a01b0319166001600160a01b038781169182179092558482166000908152606a6020526040808220805460ff199081166001908117909255938352818320805485168217905593881682529020805490911690911790558015610b74576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610918565b7fb6ad4743e88e2c9f40d48e56287cc4f2c3013181bb128d12ca2114c48fe2926690565b600080670de0b6b3a7640000600f85810b9085900b025b05905060016001607f1b03198112801590613866575060016001607f1b038113155b6040518060400160405280600281526020016127a360f11b8152509061389f5760405162461bcd60e51b81526004016109519190615584565b509392505050565b6138af614cff565b6000808360000151600f0b13156138c8575082516138cf565b5060208301515b60408051808201909152835181906138ea90600f0b8461382d565b600f0b815260200182600f0b81525091505092915050565b6033546001600160a01b03163314610dde5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610951565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6139b6614d16565b63ffffffff831660009081526020838152604091829020825160a0810184529054600381810b808452600160201b8304820b94840194909452600160401b8204810b94830194909452600160601b810490930b6060820152600160801b909204600f0b6080830152613a2c90633b9aca0061566e565b600f0b82526020810151613a479060030b633b9aca0061566e565b600f0b60208301526040810151613a659060030b633b9aca0061566e565b600f0b60408301526060810151613a839060030b633b9aca0061566e565b600f90810b6060840152608091820151900b9082015292915050565b600080613aac8484610de0565b51946000945092505050565b60006002826002811115613ace57613ace614fc7565b03613ae25750670de0b6b3a76400006114cf565b60008084600f0b12613b1b576000836002811115613b0257613b02614fc7565b14613b11578460400151613b14565b84515b9050613b47565b6000836002811115613b2f57613b2f614fc7565b14613b3e578460600151613b44565b84602001515b90505b949350505050565b63ffffffff82166000908152606d602090815260408083208484528252808320815192830190915260010154600f0b808252829182918203613b9c57600080600093509350935050613c63565b63ffffffff8087166000908152606e6020908152604080832081516060810183528154600f90810b825283518085018552600184015480830b8252600160801b90819004830b82880152838701919091528451808601865260029094015480830b855204810b9483019490945291820152805185519194613c22939290920b91613ca616565b604083015151909150600090613c3b90600f0b8361382d565b602084015151909150600090613c5490600f0b8461382d565b91975090955060009450505050505b9250925092565b6000613c9b83600f0b613c898487600f0b61382d90919063ffffffff16565b600f0b613c969190615ad7565b614a4e565b613b4790600261566e565b600081600f0b600014156040518060400160405280600381526020016222212d60e91b81525090613cea5760405162461bcd60e51b81526004016109519190615584565b50600082600f0b670de0b6b3a7640000600f0b85600f0b02816138445761384461584f565b8051600f0b600003613d28579051600f0b602090910152565b6000808260000151600f0b1315613d4157508151613d48565b5060208201515b80600f0b8260200151600f0b03613d5e57505050565b60208201518251613d77919061113690600f0b8461382d565b600f90810b83520b60209091015250565b613d90614d16565b610e6582613d9c613809565b6139ae565b336000908152606a602090815260409182902054825180840190935260018352605560f81b9183019190915260ff166132135760405162461bcd60e51b81526004016109519190615584565b6000613e016065546001600160a01b031690565b6001600160a01b0316638f4f8ecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e629190615b8a565b905090565b8151600f0b158015613e7e57506020820151600f0b155b15613e9257670de0b6b3a764000060208301525b60008260000151600f0b1315613edc57613ec082602001518360000151600f0b613ca690919063ffffffff16565b83604001818151613ed191906157ff565b600f0b905250613f12565b613efa82602001518360000151600f0b613ca690919063ffffffff16565b83606001818151613f0b919061561d565b600f0b9052505b6000808360000151600f0b1315613f2b57508251613f32565b5060208301515b81613f5b613f50856020015184600f0b613ca690919063ffffffff16565b8551600f0b9061382d565b613f65919061561d565b600f0b80845260001215613f7b57508251613f82565b5060208301515b600f81810b602085015283516000910b1315613fd257613fb683602001518460000151600f0b613ca690919063ffffffff16565b84604001818151613fc7919061561d565b600f0b905250614008565b613ff083602001518460000151600f0b613ca690919063ffffffff16565b8460600181815161400191906157ff565b600f0b9052505b50505050565b60008260000151600f0b131561403c5781516040840180516140319083906157ff565b600f0b905250614056565b815160608401805161404f90839061561d565b600f0b9052505b614061838383614b0a565b60008260000151600f0b131561408f57815160408401805161408490839061561d565b600f0b905250505050565b81516060840180516140849083906157ff565b6000806140c384600001518560400151600f0b61382d90919063ffffffff16565b905060006140e585602001518660600151600f0b61382d90919063ffffffff16565b905060006140f7600f83900b84613ca6565b63ffffffff88166000908152606b60209081526040808320815160a08101835281546001600160a01b031681526001820154600f81810b95830195909552600160801b90819004850b93820184905260029092015480850b606083015291909104830b6080820152939450919084900b900361417557506000614211565b8160200151600f0b83600f0b12156141ba576141a98260200151611136858560600151600f0b61382d90919063ffffffff16565b6141b3908261561d565b9050614211565b6141f56141e78360200151670de0b6b3a76400006141d891906157ff565b602085015161113690876157ff565b6080840151600f0b9061382d565b8260600151614204919061561d565b61420e908261561d565b90505b61422c6142216301e13380614b81565b600f83900b90613ca6565b905061424d8761424483670de0b6b3a764000061561d565b600f0b90614bf1565b95505050600061426a670de0b6b3a764000086610fa991906157ff565b9050600061428b610fa96702c68af0bb140000670de0b6b3a76400006157ff565b905060006142a761429c83856157ff565b600f88900b9061382d565b60208a01519091506142bc90600f0b8861382d565b600f0b60208a015260006142d883670de0b6b3a764000061561d565b8a519091506142ea90600f0b8261382d565b600f90810b8b5282900b156143725763ffffffff8b166000908152606d6020908152604080832083805282529182902082519182019092529054600f0b81526143348b828561400e565b63ffffffff8c166000908152606d602090815260408083208380529091529020815181546001600160801b0319166001600160801b03909116179055505b63ffffffff8b16600090815260716020526040902054600f0b156144335760006143c46143a26301e13380614b81565b63ffffffff808f16600090815260716020526040902054600f0b9190613ca616565b905060006143de8b61424484670de0b6b3a764000061561d565b60208d01519091506143f390600f0b8261382d565b600f90810b60208e01528c5161440a910b8261382d565b600f90810b8d5261441e9084900b8261382d565b925061442e600f8b900b8261382d565b995050505b6040805163ffffffff8d1681526001600160801b038b166020820152600f83810b828401528a810b606083015284900b608082015290517f6ac06550b1d7756afb13ae15bdb7f009838eeb491868f6cea5664968b8ed71fd9181900360a00190a15050505050505050505050565b600082600f0b600014806144b8575081600f0b6000145b806144d0575060006144ca868561561d565b600f0b13155b806144e8575060006144e2858461561d565b600f0b13155b156144f557506000613b47565b600082600f0b84600f0b6145099190615ad7565b90506000614517868561561d565b600f0b614524888761561d565b600f0b6145319190615ad7565b919091139695505050505050565b6001600160a01b03851661455257600080fd5b806040015160030b816000015160030b1315801561457b5750633b9aca00816040015160030b13155b80156145955750806060015160030b816020015160030b12155b80156145ac5750633b9aca00816060015160030b12155b6040518060400160405280600381526020016242504360e81b815250906145e65760405162461bcd60e51b81526004016109519190615584565b50806145f0613809565b63ffffffff8981166000818152602093845260409081902085518154958701518784015160608901516080909901516001600160801b03908116600160801b02998816600160601b0263ffffffff60601b19928916600160401b0292909216600160401b600160801b0319938916600160201b026001600160401b0319909a16949098169390931797909717169490941794909417929092169390931790915560665490516343b16a1160e11b815260048101929092526001600160a01b031690638762d42290602401600060405180830381600087803b1580156146d457600080fd5b505af11580156146e8573d6000803e3d6000fd5b5050505060688790806001815401808255809150506001900390600052602060002090600891828204019190066004029091909190916101000a81548163ffffffff021916908363ffffffff1602179055506000600160688054905061474e9190615ba7565b90505b8015614911576068614764600183615ba7565b8154811061477457614774615551565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1663ffffffff16606882815481106147b3576147b3615551565b6000918252602090912060088204015460079091166004026101000a900463ffffffff1610156148fa576000606882815481106147f2576147f2615551565b6000918252602090912060088204015460079091166004026101000a900463ffffffff1690506068614825600184615ba7565b8154811061483557614835615551565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff166068838154811061486e5761486e615551565b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908363ffffffff1602179055508060686001846148b19190615ba7565b815481106148c1576148c1615551565b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908363ffffffff160217905550506148ff565b614911565b8061490981615bbe565b915050614751565b5061491a613ded565b6001600160a01b0316632da1c59b8888888888886040518763ffffffff1660e01b815260040161494f969594939291906159a1565b600060405180830381600087803b15801561496957600080fd5b505af115801561497d573d6000803e3d6000fd5b505060405163ffffffff8a1681527f3286b0394bf1350245290b7226c92ed186bd716f28938e62dbb895298f0181729250602001905060405180910390a150505050505050565b600081600f0b83600f0b126149d957816114cf565b5090919050565b600081600f0b83600f0b136149d957816114cf565b600054610100900460ff16614a1c5760405162461bcd60e51b815260040161095190615bd5565b610dde614c79565b614a2c613902565b606580546001600160a01b0319166001600160a01b0392909216919091179055565b600080821215614a9c5760405162461bcd60e51b815260206004820152601960248201527864732d6d6174682d737172742d6e6f6e2d706f73697469766560381b6044820152606401610951565b6003821315614afb5750806000614ab4600283615b5c565b614abf906001615c20565b90505b81811215614af557905080600281614ada8186615b5c565b614ae49190615c20565b614aee9190615b5c565b9050614ac2565b50919050565b8115614b05575060015b919050565b6000808360000151600f0b1315614b2357508251614b2a565b5060208301515b82516000908390614b3e90600f0b8461382d565b614b48919061561d565b9050600081600f0b1315614b5f5784519150614b67565b846020015191505b614b75600f82900b83613ca6565b600f0b90935250505050565b6000600f82900b670de0b6b3a76400000260016001607f1b03198112801590614bb1575060016001607f1b038113155b6040518060400160405280600281526020016127a360f11b81525090614bea5760405162461bcd60e51b81526004016109519190615584565b5092915050565b60008082600f0b12156040518060400160405280600281526020016127a360f11b81525090614c335760405162461bcd60e51b81526004016109519190615584565b50670de0b6b3a764000060015b83600f0b81600f0b1361389f57808416600f0b15614c6557614c62828661382d565b91505b614c6f858661382d565b9450600202614c40565b600054610100900460ff16614ca05760405162461bcd60e51b815260040161095190615bd5565b610dde3361395c565b60405180606001604052806000600f0b8152602001614cc6614cff565b8152602001614cd3614cff565b905290565b60408051608081018252600080825260208201819052918101829052606081019190915290565b604080518082019091526000808252602082015290565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b63ffffffff8116811461321357600080fd5b600060208284031215614d6857600080fd5b81356114cf81614d44565b6001600160a01b038116811461321357600080fd5b600080600080600060a08688031215614da057600080fd5b8535614dab81614d73565b94506020860135614dbb81614d73565b93506040860135614dcb81614d73565b92506060860135614ddb81614d73565b91506080860135614deb81614d73565b809150509295509295909350565b80600f0b811461321357600080fd5b60008060408385031215614e1b57600080fd5b8235614e2681614d44565b91506020830135614e3681614df9565b809150509250929050565b60008083601f840112614e5357600080fd5b5081356001600160401b03811115614e6a57600080fd5b6020830191508360208260051b85010111156130ca57600080fd5b60008060008060408587031215614e9b57600080fd5b84356001600160401b0380821115614eb257600080fd5b614ebe88838901614e41565b90965094506020870135915080821115614ed757600080fd5b50614ee487828801614e41565b95989497509550505050565b60008060408385031215614f0357600080fd5b8235614f0e81614d44565b946020939093013593505050565b8051600f0b82526020810151600f0b60208301525050565b8051600f0b82526020810151600f0b60208301526040810151600f0b60408301526060810151600f0b60608301525050565b8451600f0b8152602080860151610180830191614f8590840182614f1c565b506040860151614f986060840182614f1c565b508451600f0b60a0830152614fb060c0830185614f34565b614fbe610140830184614f1c565b95945050505050565b634e487b7160e01b600052602160045260246000fd5b6020810160028310614fff57634e487b7160e01b600052602160045260246000fd5b91905290565b6020808252825182820181905260009190848201906040850190845b8181101561504357835163ffffffff1683529284019291840191600101615021565b50909695505050505050565b60408101610e658284614f1c565b803560038110614b0557600080fd5b6000806040838503121561507f57600080fd5b8235915061508f6020840161505d565b90509250929050565b6000602082840312156150aa57600080fd5b5035919050565b6000806000606084860312156150c657600080fd5b8335925060208401356150d881614d44565b91506150e66040850161505d565b90509250925092565b600080600080600060a0868803121561510757600080fd5b853561511281614d44565b945060208601359350604086013561512981614df9565b9250606086013561513981614df9565b91506080860135614deb81614df9565b60006020828403121561515b57600080fd5b81356001600160801b03811681146114cf57600080fd5b6000806040838503121561518557600080fd5b50508035926020909101359150565b60405160a081016001600160401b03811182821017156151c457634e487b7160e01b600052604160045260246000fd5b60405290565b60405160c081016001600160401b03811182821017156151c457634e487b7160e01b600052604160045260246000fd5b8035600381900b8114614b0557600080fd5b600060a0828403121561521e57600080fd5b615226615194565b9050615231826151fa565b815261523f602083016151fa565b6020820152615250604083016151fa565b6040820152615261606083016151fa565b6060820152608082013561527481614df9565b608082015292915050565b60008060c0838503121561529257600080fd5b823561529d81614d44565b915061508f846020850161520c565b6000806000606084860312156152c157600080fd5b83356152cc81614d44565b925060208401356152dc81614df9565b915060408401356152ec81614df9565b809150509250925092565b6000806020838503121561530a57600080fd5b82356001600160401b038082111561532157600080fd5b818501915085601f83011261533557600080fd5b81358181111561534457600080fd5b86602082850101111561535657600080fd5b60209290920196919550909350505050565b600060a08284031215614af557600080fd5b600080600080600080600080610200898b03121561539757600080fd5b88356153a281614d44565b975060208901356153b281614d44565b965060408901356153c281614d73565b955060608901356153d281614df9565b945060808901356153e281614df9565b935060a08901356153f281614df9565b92506154018a60c08b01615368565b91506154118a6101608b01615368565b90509295985092959890939650565b60008060006060848603121561543557600080fd5b833561544081614d44565b92506020840135915060408401356152ec81614df9565b60c081016154658285614f34565b6114cf6080830184614f1c565b60006020828403121561548457600080fd5b81356114cf81614d73565b600080604083850312156154a257600080fd5b823591506020830135614e3681614df9565b600080600080608085870312156154ca57600080fd5b84356154d581614d44565b93506020850135925060408501356154ec81614df9565b915060608501356154fc81614df9565b939692955090935050565b6020808252602a908201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686040820152691948195b991c1bda5b9d60b21b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561557957600080fd5b81356114cf81614df9565b600060208083528351808285015260005b818110156155b157858101830151858201604001528201615595565b818111156155c3576000604083870101525b50601f01601f1916929092016040019392505050565b634e487b7160e01b600052601160045260246000fd5b60006001600160801b038281166002600160801b03198101615613576156136155d9565b6001019392505050565b6000600f82810b9084900b828212801560016001607f1b0384900383131615615648576156486155d9565b60016001607f1b03198390038212811615615665576156656155d9565b50019392505050565b6000600f82810b9084900b60016001607f1b038382138484138082168484048611161561569d5761569d6155d9565b60016001607f1b031960008512828116878305871216156156c0576156c06155d9565b600087129250858205871284841616156156dc576156dc6155d9565b858505871281841616156156f2576156f26155d9565b5050509290910295945050505050565b600063ffffffff808316818103615613576156136155d9565b60006080828403121561572d57600080fd5b604051608081018181106001600160401b038211171561575d57634e487b7160e01b600052604160045260246000fd5b604052825161576b81614d44565b8152602083015161577b81614df9565b6020820152604083015161578e81614df9565b604082015260608301516157a181614df9565b60608201529392505050565b6000600f82900b6001607f1b81016157c7576157c76155d9565b60000392915050565b60006001600160401b03808316818516818304811182151516156157f6576157f66155d9565b02949350505050565b6000600f82810b9084900b828112801560016001607f1b031983018412161561582a5761582a6155d9565b60016001607f1b0382018313811615615845576158456155d9565b5090039392505050565b634e487b7160e01b600052601260045260246000fd5b600081600f0b83600f0b8061587c5761587c61584f565b60016001607f1b031982146000198214161561589a5761589a6155d9565b90059392505050565b60008183036101c08112156158b757600080fd5b6158bf6151ca565b83356158ca81614d44565b815260208401356158da81614df9565b602082015260408401356158ed81614df9565b6040820152606084013561590081614df9565b606082015260a0607f198301121561591757600080fd5b61591f615194565b9150608084013561592f81614d73565b825260a084013561593f81614df9565b602083015260c084013561595281614df9565b604083015260e084013561596581614df9565b606083015261010084013561597981614df9565b8060808401525081608082015261599485610120860161520c565b60a0820152949350505050565b63ffffffff96871681529490951660208501526001600160a01b03929092166040840152600f90810b606084015290810b60808301529190910b60a082015260c00190565b600060a082840312156159f857600080fd5b6114cf838361520c565b80546001600160801b0319166001600160801b0392909216919091179055565b80546001600160801b031660809290921b6001600160801b031916919091179055565b8135615a5081614d73565b81546001600160a01b0319166001600160a01b0391909116178155600181016020830135615a7d81614df9565b615a878183615a02565b506040830135615a9681614df9565b615aa08183615a22565b5050600281016060830135615ab481614df9565b615abe8183615a02565b506080830135615acd81614df9565b6140088183615a22565b60006001600160ff1b0381841382841380821686840486111615615afd57615afd6155d9565b600160ff1b6000871282811687830589121615615b1c57615b1c6155d9565b60008712925087820587128484161615615b3857615b386155d9565b87850587128184161615615b4e57615b4e6155d9565b505050929093029392505050565b600082615b6b57615b6b61584f565b600160ff1b821460001984141615615b8557615b856155d9565b500590565b600060208284031215615b9c57600080fd5b81516114cf81614d73565b600082821015615bb957615bb96155d9565b500390565b600081615bcd57615bcd6155d9565b506000190190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600080821280156001600160ff1b0384900385131615615c4257615c426155d9565b600160ff1b8390038412811615615c5b57615c5b6155d9565b5050019056feda90043ba5b4096ba14704bc227ab0d3167da15b887e62ab2e76e37daa7113567febd347df14ea35c529e50fb2dd629d4a6226f5ccc893710fb466f8b83823fc7febd347df14ea35c529e50fb2dd629d4a6226f5ccc893710fb466f8b83823fda26469706673582212205279aacced1dc7ea5d493c412e6e4fb5665edd3ea4fdee4ece80efdf59782f2d64736f6c634300080d0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.