Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Initialize | 2722166 | 54 days ago | IN | 0 S | 0.00026337 |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Clearinghouse
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 800 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 "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "./common/Constants.sol"; import "./interfaces/clearinghouse/IClearinghouse.sol"; import "./interfaces/engine/IProductEngine.sol"; import "./interfaces/engine/ISpotEngine.sol"; import "./interfaces/IOffchainExchange.sol"; import "./libraries/ERC20Helper.sol"; import "./libraries/MathHelper.sol"; import "./libraries/Logger.sol"; import "./libraries/MathSD21x18.sol"; import "./interfaces/engine/IPerpEngine.sol"; import "./EndpointGated.sol"; import "./interfaces/IEndpoint.sol"; import "./ClearinghouseStorage.sol"; import "./WithdrawPool.sol"; interface IProxyManager { function getProxyManagerHelper() external view returns (address); function getCodeHash(string memory name) external view returns (bytes32); } enum YieldMode { AUTOMATIC, DISABLED, CLAIMABLE } enum GasMode { VOID, CLAIMABLE } interface IBlastPoints { function configurePointsOperator(address operator) external; } interface IBlast { function configure( YieldMode _yield, GasMode gasMode, address governor ) external; } contract Clearinghouse is EndpointGated, ClearinghouseStorage, IClearinghouse { using MathSD21x18 for int128; using ERC20Helper for IERC20Base; function initialize( address _endpoint, address _quote, address _clearinghouseLiq, uint256 _spreads, address _withdrawPool ) external initializer { __Ownable_init(); setEndpoint(_endpoint); quote = _quote; clearinghouse = address(this); clearinghouseLiq = _clearinghouseLiq; spreads = _spreads; withdrawPool = _withdrawPool; emit ClearinghouseInitialized(_endpoint, _quote); } /** * View */ function getQuote() external view returns (address) { return quote; } function getEngineByType(IProductEngine.EngineType engineType) external view returns (address) { return address(engineByType[engineType]); } function getEngineByProduct(uint32 productId) external view returns (address) { return address(productToEngine[productId]); } function getInsurance() external view returns (int128) { return insurance; } /// @notice grab total subaccount health function getHealth(bytes32 subaccount, IProductEngine.HealthType healthType) public view returns (int128 health) { ISpotEngine spotEngine = ISpotEngine( address(engineByType[IProductEngine.EngineType.SPOT]) ); IPerpEngine perpEngine = IPerpEngine( address(engineByType[IProductEngine.EngineType.PERP]) ); health = spotEngine.getHealthContribution(subaccount, healthType); // min health means that it is attempting to borrow a spot that exists outside // of the risk system -- return min health to error out this action if (health == (type(int128).min)) { return health; } uint256 _spreads = spreads; while (_spreads != 0) { uint32 _spotId = uint32(_spreads & 0xFF); _spreads >>= 8; uint32 _perpId = uint32(_spreads & 0xFF); _spreads >>= 8; IProductEngine.CoreRisk memory perpCoreRisk = perpEngine .getCoreRisk(subaccount, _perpId, healthType); if (perpCoreRisk.amount == 0) { continue; } IProductEngine.CoreRisk memory spotCoreRisk = spotEngine .getCoreRisk(subaccount, _spotId, healthType); if ( (spotCoreRisk.amount == 0) || ((spotCoreRisk.amount > 0) == (perpCoreRisk.amount > 0)) ) { continue; } int128 basisAmount; if (spotCoreRisk.amount > 0) { basisAmount = MathHelper.min( spotCoreRisk.amount, -perpCoreRisk.amount ); } else { basisAmount = -MathHelper.max( spotCoreRisk.amount, -perpCoreRisk.amount ); } int128 existingPenalty = (spotCoreRisk.longWeight + perpCoreRisk.longWeight) / 2; int128 spreadPenalty; if (spotCoreRisk.amount > 0) { spreadPenalty = ONE - (ONE - perpCoreRisk.longWeight) / 5; } else { spreadPenalty = ONE - (ONE - spotCoreRisk.longWeight) / 5; } health += basisAmount .mul(spotCoreRisk.price + perpCoreRisk.price) .mul(spreadPenalty - existingPenalty); } health += perpEngine.getHealthContribution(subaccount, healthType); } function registerProduct(uint32 productId) external { IProductEngine engine = IProductEngine(msg.sender); IProductEngine.EngineType engineType = engine.getEngineType(); require( address(engineByType[engineType]) == msg.sender, ERR_UNAUTHORIZED ); productToEngine[productId] = engine; } /** * Actions */ function addEngine( address engine, address offchainExchange, IProductEngine.EngineType engineType ) external onlyOwner { require(address(engineByType[engineType]) == address(0)); require(engine != address(0)); IProductEngine productEngine = IProductEngine(engine); // Register supportedEngines.push(engineType); engineByType[engineType] = productEngine; // add quote to product mapping if (engineType == IProductEngine.EngineType.SPOT) { productToEngine[QUOTE_PRODUCT_ID] = productEngine; } // Initialize engine productEngine.initialize( address(this), offchainExchange, quote, getEndpoint(), owner() ); } function _tokenAddress(uint32 productId) internal view returns (address) { ISpotEngine spotEngine = ISpotEngine( address(engineByType[IProductEngine.EngineType.SPOT]) ); return spotEngine.getConfig(productId).token; } function _decimals(uint32 productId) internal virtual returns (uint8) { IERC20Base token = IERC20Base(_tokenAddress(productId)); require(address(token) != address(0)); return token.decimals(); } function depositCollateral(IEndpoint.DepositCollateral calldata txn) external virtual onlyEndpoint { require(!RiskHelper.isIsolatedSubaccount(txn.sender), ERR_UNAUTHORIZED); require(txn.amount <= INT128_MAX, ERR_CONVERSION_OVERFLOW); ISpotEngine spotEngine = ISpotEngine( address(engineByType[IProductEngine.EngineType.SPOT]) ); uint8 decimals = _decimals(txn.productId); require(decimals <= MAX_DECIMALS); int256 multiplier = int256(10**(MAX_DECIMALS - decimals)); int128 amountRealized = int128(txn.amount) * int128(multiplier); spotEngine.updateBalance(txn.productId, txn.sender, amountRealized); emit ModifyCollateral(amountRealized, txn.sender, txn.productId); } function transferQuote(IEndpoint.TransferQuote calldata txn) external virtual onlyEndpoint { require(txn.amount <= INT128_MAX, ERR_CONVERSION_OVERFLOW); int128 toTransfer = int128(txn.amount); ISpotEngine spotEngine = ISpotEngine( address(engineByType[IProductEngine.EngineType.SPOT]) ); // require the sender address to be the same as the recipient address // otherwise linked signers can transfer out require( bytes20(txn.sender) == bytes20(txn.recipient), ERR_UNAUTHORIZED ); address offchainExchange = IEndpoint(getEndpoint()) .getOffchainExchange(); if (RiskHelper.isIsolatedSubaccount(txn.sender)) { // isolated subaccounts can only transfer quote back to parent require( IOffchainExchange(offchainExchange).getParentSubaccount( txn.sender ) == txn.recipient, ERR_UNAUTHORIZED ); } else if (RiskHelper.isIsolatedSubaccount(txn.recipient)) { // regular subaccounts can transfer quote to active isolated subaccounts require( IOffchainExchange(offchainExchange).isIsolatedSubaccountActive( txn.sender, txn.recipient ), ERR_UNAUTHORIZED ); } spotEngine.updateBalance(QUOTE_PRODUCT_ID, txn.sender, -toTransfer); spotEngine.updateBalance(QUOTE_PRODUCT_ID, txn.recipient, toTransfer); require(_isAboveInitial(txn.sender), ERR_SUBACCT_HEALTH); } function depositInsurance(bytes calldata transaction) external virtual onlyEndpoint { IEndpoint.DepositInsurance memory txn = abi.decode( transaction[1:], (IEndpoint.DepositInsurance) ); require(txn.amount <= INT128_MAX, ERR_CONVERSION_OVERFLOW); int256 multiplier = int256( 10**(MAX_DECIMALS - _decimals(QUOTE_PRODUCT_ID)) ); int128 amount = int128(txn.amount) * int128(multiplier); insurance += amount; } function withdrawInsurance(bytes calldata transaction, uint64 idx) external virtual onlyEndpoint { IEndpoint.WithdrawInsurance memory txn = abi.decode( transaction[1:], (IEndpoint.WithdrawInsurance) ); require(txn.amount <= INT128_MAX, ERR_CONVERSION_OVERFLOW); int256 multiplier = int256( 10**(MAX_DECIMALS - _decimals(QUOTE_PRODUCT_ID)) ); int128 amount = int128(txn.amount) * int128(multiplier); require(amount <= insurance, ERR_NO_INSURANCE); insurance -= amount; ISpotEngine spotEngine = ISpotEngine( address(engineByType[IProductEngine.EngineType.SPOT]) ); IERC20Base token = IERC20Base( spotEngine.getConfig(QUOTE_PRODUCT_ID).token ); require(address(token) != address(0)); handleWithdrawTransfer(token, txn.sendTo, txn.amount, idx); } function handleWithdrawTransfer( IERC20Base token, address to, uint128 amount, uint64 idx ) internal virtual { token.safeTransfer(withdrawPool, uint256(amount)); WithdrawPool(withdrawPool).submitWithdrawal(token, to, amount, idx); } function _balanceOf(address token) internal view virtual returns (uint128) { return uint128(IERC20Base(token).balanceOf(address(this))); } function withdrawCollateral( bytes32 sender, uint32 productId, uint128 amount, address sendTo, uint64 idx ) external virtual onlyEndpoint { require(!RiskHelper.isIsolatedSubaccount(sender), ERR_UNAUTHORIZED); require(amount <= INT128_MAX, ERR_CONVERSION_OVERFLOW); ISpotEngine spotEngine = ISpotEngine( address(engineByType[IProductEngine.EngineType.SPOT]) ); IERC20Base token = IERC20Base(spotEngine.getConfig(productId).token); require(address(token) != address(0)); if (sender != X_ACCOUNT) { sendTo = address(uint160(bytes20(sender))); } handleWithdrawTransfer(token, sendTo, amount, idx); int256 multiplier = int256(10**(MAX_DECIMALS - _decimals(productId))); int128 amountRealized = -int128(amount) * int128(multiplier); spotEngine.updateBalance(productId, sender, amountRealized); spotEngine.assertUtilization(productId); IProductEngine.HealthType healthType = sender == X_ACCOUNT ? IProductEngine.HealthType.PNL : IProductEngine.HealthType.INITIAL; require(getHealth(sender, healthType) >= 0, ERR_SUBACCT_HEALTH); // TODO: remove this when we support wS spot. if (productId == 145) { ISpotEngine.Balance memory balance = spotEngine.getBalance( productId, sender ); require(balance.amount >= 0, ERR_SUBACCT_HEALTH); } emit ModifyCollateral(amountRealized, sender, productId); } function mintLp(IEndpoint.MintLp calldata txn) external virtual onlyEndpoint { require(!RiskHelper.isIsolatedSubaccount(txn.sender), ERR_UNAUTHORIZED); require(txn.productId != QUOTE_PRODUCT_ID); // TODO: remove this when we support wS spot. require(txn.productId != 145, ERR_INVALID_PRODUCT); productToEngine[txn.productId].mintLp( txn.productId, txn.sender, int128(txn.amountBase), int128(txn.quoteAmountLow), int128(txn.quoteAmountHigh) ); require(_isAboveInitial(txn.sender), ERR_SUBACCT_HEALTH); } function burnLp(IEndpoint.BurnLp calldata txn) external virtual onlyEndpoint { require(!RiskHelper.isIsolatedSubaccount(txn.sender), ERR_UNAUTHORIZED); productToEngine[txn.productId].burnLp( txn.productId, txn.sender, int128(txn.amount) ); } function burnLpAndTransfer(IEndpoint.BurnLpAndTransfer calldata txn) external virtual onlyEndpoint { require(!RiskHelper.isIsolatedSubaccount(txn.sender), ERR_UNAUTHORIZED); require( !RiskHelper.isIsolatedSubaccount(txn.recipient), ERR_UNAUTHORIZED ); ISpotEngine spotEngine = ISpotEngine( address(engineByType[IProductEngine.EngineType.SPOT]) ); require(spotEngine == productToEngine[txn.productId]); (int128 amountBase, int128 amountQuote) = spotEngine.burnLp( txn.productId, txn.sender, int128(txn.amount) ); spotEngine.updateBalance(QUOTE_PRODUCT_ID, txn.sender, -amountQuote); spotEngine.updateBalance(QUOTE_PRODUCT_ID, txn.recipient, amountQuote); spotEngine.updateBalance(txn.productId, txn.sender, -amountBase); spotEngine.updateBalance(txn.productId, txn.recipient, amountBase); require(_isAboveInitial(txn.sender), ERR_SUBACCT_HEALTH); } function claimSequencerFees( IEndpoint.ClaimSequencerFees calldata txn, int128[] calldata fees ) external virtual onlyEndpoint { require( !RiskHelper.isIsolatedSubaccount(txn.subaccount), ERR_UNAUTHORIZED ); ISpotEngine spotEngine = ISpotEngine( address(engineByType[IProductEngine.EngineType.SPOT]) ); IPerpEngine perpEngine = IPerpEngine( address(engineByType[IProductEngine.EngineType.PERP]) ); uint32[] memory spotIds = spotEngine.getProductIds(); uint32[] memory perpIds = perpEngine.getProductIds(); for (uint256 i = 0; i < spotIds.length; i++) { ISpotEngine.Balance memory feeBalance = spotEngine.getBalance( spotIds[i], FEES_ACCOUNT ); spotEngine.updateBalance( spotIds[i], txn.subaccount, fees[i] + feeBalance.amount ); spotEngine.updateBalance( spotIds[i], FEES_ACCOUNT, -feeBalance.amount ); } for (uint256 i = 0; i < perpIds.length; i++) { IPerpEngine.Balance memory feeBalance = perpEngine.getBalance( perpIds[i], FEES_ACCOUNT ); perpEngine.updateBalance( perpIds[i], txn.subaccount, feeBalance.amount, feeBalance.vQuoteBalance ); perpEngine.updateBalance( perpIds[i], FEES_ACCOUNT, -feeBalance.amount, -feeBalance.vQuoteBalance ); } } function _settlePnl(bytes32 subaccount, uint256 productIds) internal { IPerpEngine perpEngine = IPerpEngine( address(engineByType[IProductEngine.EngineType.PERP]) ); int128 amountSettled = perpEngine.settlePnl(subaccount, productIds); ISpotEngine(address(engineByType[IProductEngine.EngineType.SPOT])) .updateBalance(QUOTE_PRODUCT_ID, subaccount, amountSettled); } function settlePnl(bytes calldata transaction) external onlyEndpoint { IEndpoint.SettlePnl memory txn = abi.decode( transaction[1:], (IEndpoint.SettlePnl) ); for (uint128 i = 0; i < txn.subaccounts.length; ++i) { _settlePnl(txn.subaccounts[i], txn.productIds[i]); } } function _isAboveInitial(bytes32 subaccount) internal view returns (bool) { // Weighted initial health with limit orders < 0 return getHealth(subaccount, IProductEngine.HealthType.INITIAL) >= 0; } function _isUnderMaintenance(bytes32 subaccount) internal view returns (bool) { // Weighted maintenance health < 0 return getHealth(subaccount, IProductEngine.HealthType.MAINTENANCE) < 0; } function liquidateSubaccount(IEndpoint.LiquidateSubaccount calldata txn) external virtual onlyEndpoint { bytes4 liquidateSubaccountSelector = bytes4( keccak256( "liquidateSubaccountImpl((bytes32,bytes32,uint32,bool,int128,uint64))" ) ); bytes memory liquidateSubaccountCall = abi.encodeWithSelector( liquidateSubaccountSelector, txn ); (bool success, bytes memory result) = clearinghouseLiq.delegatecall( liquidateSubaccountCall ); require(success, string(result)); } struct AddressSlot { address value; } function _getProxyManager() internal view returns (address) { AddressSlot storage proxyAdmin; assembly { proxyAdmin.slot := 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 } return proxyAdmin.value; } function upgradeClearinghouseLiq(address _clearinghouseLiq) external { require( msg.sender == IProxyManager(_getProxyManager()).getProxyManagerHelper(), ERR_UNAUTHORIZED ); clearinghouseLiq = _clearinghouseLiq; } function getClearinghouseLiq() external view returns (address) { return clearinghouseLiq; } function getSpreads() external view returns (uint256) { return spreads; } function configurePoints( address blastPoints, address blast, address gov ) external onlyOwner { IBlastPoints(blastPoints).configurePointsOperator(gov); IBlast(blast).configure(YieldMode.CLAIMABLE, GasMode.CLAIMABLE, gov); } function requireMinDeposit(uint32 productId, uint128 amount) external { require(amount <= INT128_MAX, ERR_CONVERSION_OVERFLOW); uint8 decimals = _decimals(productId); require(decimals <= MAX_DECIMALS); int256 multiplier = int256(10**(MAX_DECIMALS - decimals)); int128 amountRealized = int128(multiplier) * int128(amount); int128 priceX18 = ONE; if (productId != QUOTE_PRODUCT_ID) { priceX18 = IEndpoint(getEndpoint()).getPriceX18(productId); } require( priceX18.mul(amountRealized) >= MIN_DEPOSIT_AMOUNT, ERR_DEPOSIT_TOO_SMALL ); } function assertCode(bytes calldata transaction) external view virtual { IEndpoint.AssertCode memory txn = abi.decode( transaction[1:], (IEndpoint.AssertCode) ); require( txn.contractNames.length == txn.codeHashes.length, ERR_CODE_NOT_MATCH ); for (uint256 i = 0; i < txn.contractNames.length; i++) { bytes32 expectedCodeHash = IProxyManager(_getProxyManager()) .getCodeHash(txn.contractNames[i]); require(txn.codeHashes[i] == expectedCodeHash, ERR_CODE_NOT_MATCH); } } function manualAssert(bytes calldata transaction) external view virtual { IEndpoint.ManualAssert memory txn = abi.decode( transaction[1:], (IEndpoint.ManualAssert) ); ISpotEngine spotEngine = ISpotEngine( address(engineByType[IProductEngine.EngineType.SPOT]) ); IPerpEngine perpEngine = IPerpEngine( address(engineByType[IProductEngine.EngineType.PERP]) ); perpEngine.manualAssert(txn.openInterests); spotEngine.manualAssert(txn.totalDeposits, txn.totalBorrows); } function getWithdrawPool() external view returns (address) { return withdrawPool; } function setWithdrawPool(address _withdrawPool) external onlyOwner { require(_withdrawPool != address(0)); withdrawPool = _withdrawPool; } function getSlowModeFee() external view returns (uint256) { ISpotEngine spotEngine = ISpotEngine( address(engineByType[IProductEngine.EngineType.SPOT]) ); IERC20Base token = IERC20Base( spotEngine.getConfig(QUOTE_PRODUCT_ID).token ); int256 multiplier = int256(10**(token.decimals() - 6)); return uint256(int256(SLOW_MODE_FEE) * multiplier); } }
// 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 // 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 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) (utils/cryptography/draft-EIP712.sol) pragma solidity ^0.8.0; // EIP-712 is Final as of 2022-08-11. This file is deprecated. import "./EIP712Upgradeable.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../StringsUpgradeable.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSAUpgradeable { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.0; import "./ECDSAUpgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ * * @custom:storage-size 52 */ abstract contract EIP712Upgradeable is Initializable { /* solhint-disable var-name-mixedcase */ bytes32 private _HASHED_NAME; bytes32 private _HASHED_VERSION; bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ function __EIP712_init(string memory name, string memory version) internal onlyInitializing { __EIP712_init_unchained(name, version); } function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing { bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash()); } function _buildDomainSeparator( bytes32 typeHash, bytes32 nameHash, bytes32 versionHash ) private view returns (bytes32) { return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712NameHash() internal virtual view returns (bytes32) { return _HASHED_NAME; } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712VersionHash() internal virtual view returns (bytes32) { return _HASHED_VERSION; } /** * @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) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { 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 = MathUpgradeable.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, MathUpgradeable.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.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// 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); } } }
// 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: GPL-2.0-or-later pragma solidity ^0.8.0; import "./interfaces/engine/IProductEngine.sol"; abstract contract ClearinghouseStorage { using MathSD21x18 for int128; struct LegacyHealthGroup { uint32 spotId; uint32 perpId; } struct LegacyRiskStore { int32 longWeightInitial; int32 shortWeightInitial; int32 longWeightMaintenance; int32 shortWeightMaintenance; int32 largePositionPenalty; } uint32 internal maxHealthGroup; // deprecated mapping(uint32 => LegacyHealthGroup) internal healthGroups; // deprecated mapping(uint32 => LegacyRiskStore) internal risks; // deprecated // Each clearinghouse has a quote ERC20 address internal quote; address internal clearinghouse; address internal clearinghouseLiq; // fee calculator address internal fees; // Number of products registered across all engines uint32 internal numProducts; // deprecated // product ID -> engine address mapping(uint32 => IProductEngine) internal productToEngine; // Type to engine address mapping(IProductEngine.EngineType => IProductEngine) internal engineByType; // Supported engine types IProductEngine.EngineType[] internal supportedEngines; // insurance stuff, consider making it its own subaccount later int128 internal insurance; int128 internal lastLiquidationFees; uint256 internal spreads; address internal withdrawPool; function getLiqPriceX18(uint32 productId, int128 amount) internal view returns (int128, int128) { RiskHelper.Risk memory risk = IProductEngine(productToEngine[productId]) .getRisk(productId); return ( risk.priceX18.mul( ONE + (RiskHelper._getWeightX18( risk, amount, IProductEngine.HealthType.MAINTENANCE ) - ONE) / 5 ), risk.priceX18 ); } function getSpreadLiqPriceX18( uint32 spotId, uint32 perpId, int128 amount ) internal view returns ( int128, int128, int128 ) { RiskHelper.Risk memory spotRisk = IProductEngine( productToEngine[spotId] ).getRisk(spotId); RiskHelper.Risk memory perpRisk = IProductEngine( productToEngine[perpId] ).getRisk(perpId); int128 spreadPenaltyX18; if (amount >= 0) { spreadPenaltyX18 = (ONE - RiskHelper._getWeightX18( perpRisk, amount, IProductEngine.HealthType.MAINTENANCE )) / 25; } else { spreadPenaltyX18 = (RiskHelper._getWeightX18( spotRisk, amount, IProductEngine.HealthType.MAINTENANCE ) - ONE) / 25; } if (amount > 0) { return ( spotRisk.priceX18.mul(ONE - spreadPenaltyX18), spotRisk.priceX18, perpRisk.priceX18 ); } else { return ( spotRisk.priceX18.mul(ONE + spreadPenaltyX18), spotRisk.priceX18, perpRisk.priceX18 ); } } }
// 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 "@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: 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; 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 "./IProductEngine.sol"; import "../../libraries/RiskHelper.sol"; interface IPerpEngine is IProductEngine { event FundingPayment( uint32 productId, uint128 dt, int128 openInterest, int128 payment ); struct State { int128 cumulativeFundingLongX18; int128 cumulativeFundingShortX18; int128 availableSettle; int128 openInterest; } struct Balance { int128 amount; int128 vQuoteBalance; int128 lastCumulativeFundingX18; } struct LpState { int128 supply; // TODO: this should be removed; we can just get it from State.cumulativeFundingLongX18 int128 lastCumulativeFundingX18; int128 cumulativeFundingPerLpX18; int128 base; int128 quote; } struct LpBalance { int128 amount; // NOTE: funding payments should be rolled // into Balance.vQuoteBalance; int128 lastCumulativeFundingX18; } struct UpdateProductTx { uint32 productId; int128 sizeIncrement; int128 minSize; int128 lpSpreadX18; 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 ); /// @dev Returns amount settled and emits SettlePnl events for each product function settlePnl(bytes32 subaccount, uint256 productIds) external returns (int128); function getSettlementState(uint32 productId, bytes32 subaccount) external view returns ( int128 availableSettle, LpState memory lpState, LpBalance memory lpBalance, State memory state, Balance memory balance ); function updateBalance( uint32 productId, bytes32 subaccount, int128 amountDelta, int128 vQuoteDelta ) external; function updateStates(uint128 dt, int128[] calldata avgPriceDiffs) external; function manualAssert(int128[] calldata openInterests) external view; function getPositionPnl(uint32 productId, bytes32 subaccount) external view returns (int128); function socializeSubaccount(bytes32 subaccount, int128 insurance) external returns (int128); }
// 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: 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 "./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: GPL-2.0-or-later pragma solidity ^0.8.0; interface IERC20Base { function decimals() external view returns (uint8); /** * @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 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); function increaseAllowance(address spender, uint256 addedValue) external returns (bool); function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); function balanceOf(address account) external view returns (uint256); }
// 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 ); event CloseIsolatedSubaccount( bytes32 indexed isolatedSubaccount, bytes32 indexed parentSubaccount ); 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: UNLICENSED pragma solidity ^0.8.0; interface IVerifier { function requireValidSignature( bytes32 message, bytes32 e, bytes32 s, uint8 signerBitmask ) external; function revertGasInfo(uint256 i, uint256 gasUsed) external pure; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "../interfaces/IERC20Base.sol"; import "../common/Errors.sol"; import "hardhat/console.sol"; // @dev Adapted from https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/TransferHelper.sol library ERC20Helper { function safeTransfer( IERC20Base self, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(self).call( abi.encodeWithSelector(IERC20Base.transfer.selector, to, amount) ); require( success && (data.length == 0 || abi.decode(data, (bool))), ERR_TRANSFER_FAILED ); } function safeTransferFrom( IERC20Base self, address from, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(self).call( abi.encodeWithSelector( IERC20Base.transferFrom.selector, from, to, amount ) ); require( success && (data.length == 0 || abi.decode(data, (bool))), ERR_TRANSFER_FAILED ); } }
// 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: 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 "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "./common/Errors.sol"; import "./libraries/MathHelper.sol"; import "./interfaces/IVerifier.sol"; contract Verifier is EIP712Upgradeable, OwnableUpgradeable, IVerifier { Point[8] internal pubkeys; Point[256] internal aggregatePubkey; bool[256] internal isAggregatePubkeyLatest; uint256 internal nSigner; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize(Point[8] memory initialSet) external initializer { __Ownable_init(); for (uint256 i = 0; i < 8; ++i) { if (!isPointNone(initialSet[i])) { _assignPubkey(i, initialSet[i].x, initialSet[i].y); } } } function revertGasInfo(uint256 i, uint256 gasUsed) external pure { revert( string.concat( "G ", MathHelper.uint2str(uint128(i)), " ", MathHelper.uint2str(uint128(gasUsed)) ) ); } function assignPubKey( uint256 i, uint256 x, uint256 y ) public onlyOwner { _assignPubkey(i, x, y); } function _assignPubkey( uint256 i, uint256 x, uint256 y ) internal { require(i < 8); if (isPointNone(pubkeys[i])) { nSigner += 1; } pubkeys[i] = Point(x, y); for (uint256 s = (1 << i); s < 256; s = (s + 1) | (1 << i)) { isAggregatePubkeyLatest[s] = false; } } function deletePubkey(uint256 index) public onlyOwner { if (!isPointNone(pubkeys[index])) { nSigner -= 1; delete pubkeys[index]; } } function getPubkey(uint8 index) public view returns (Point memory) { return pubkeys[index]; } function getPubkeyAddress(uint8 index) public view returns (address) { Point memory p = getPubkey(index); return address(uint160(uint256(keccak256(abi.encode(p.x, p.y))))); } function getAggregatePubkey(uint8 signerBitmask) internal returns (Point memory) { if (signerBitmask == 0 || isAggregatePubkeyLatest[signerBitmask]) return aggregatePubkey[signerBitmask]; Point memory res; for (uint256 i = 0; i < 8; ++i) { if ((signerBitmask >> i) % 2 == 1) { require(!isPointNone(pubkeys[i])); res = pointAdd( getAggregatePubkey(signerBitmask ^ uint8(1 << i)), pubkeys[i] ); break; } } aggregatePubkey[signerBitmask] = res; isAggregatePubkeyLatest[signerBitmask] = true; return res; } // determine if 2/3 of the signers are included in this signing mask // and if the keys are present function checkQuorum(uint8 signerBitmask) internal view returns (bool) { uint256 nSigned = 0; for (uint256 i = 0; i < 8; ++i) { bool signed = ((signerBitmask >> i) & 1) == 1; if (signed) { if (isPointNone(pubkeys[i])) { return false; } nSigned += 1; } } return nSigned * 2 > nSigner; } function requireValidSignature( bytes32 message, bytes32 e, bytes32 s, uint8 signerBitmask ) public { require(checkQuorum(signerBitmask)); Point memory pubkey = getAggregatePubkey(signerBitmask); require( verify( pubkey.y % 2 == 0 ? 27 : 28, bytes32(pubkey.x), message, e, s ), "Verification failed" ); } /// SCHNORR IMPLEMENTATION BELOW // secp256k1 group order uint256 public constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; // parity := public key y-coord parity (27 or 28) // px := public key x-coord // message := 32-byte message // e := schnorr signature challenge // s := schnorr signature function verify( uint8 parity, bytes32 px, bytes32 message, bytes32 e, bytes32 s ) internal pure returns (bool) { // ecrecover = (m, v, r, s); bytes32 sp = bytes32(Q - mulmod(uint256(s), uint256(px), Q)); bytes32 ep = bytes32(Q - mulmod(uint256(e), uint256(px), Q)); require(sp != 0); // the ecrecover precompile implementation checks that the `r` and `s` // inputs are non-zero (in this case, `px` and `ep`), thus we don't need to // check if they're zero. address R = ecrecover(sp, parity, px, ep); require(R != address(0), "ecrecover failed"); return e == keccak256(abi.encodePacked(R, uint8(parity), px, message)); } uint256 public constant _P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; struct Point { uint256 x; uint256 y; } function pow( uint256 a, uint256 b, uint256 mod ) internal pure returns (uint256) { // a ^ b % mod uint256 res = 1; while (b > 0) { if (b % 2 == 1) { res = mulmod(res, a, mod); } a = mulmod(a, a, mod); b /= 2; } return res; } function isPointNone(Point memory u) internal pure returns (bool) { return u.x == 0 && u.y == 0; } function pointAdd(Point memory u, Point memory v) internal pure returns (Point memory) { if (isPointNone(u)) return v; if (isPointNone(v)) return u; uint256 lam = 0; if (u.x == v.x) { if (u.y != v.y) return Point(0, 0); lam = mulmod(3, u.x, _P); lam = mulmod(lam, u.x, _P); lam = mulmod(lam, pow(mulmod(2, v.y, _P), _P - 2, _P), _P); } else { lam = mulmod( addmod(v.y, _P - u.y, _P), pow(addmod(v.x, _P - u.x, _P), _P - 2, _P), _P ); } uint256 x3 = mulmod(lam, lam, _P); x3 = addmod(x3, _P - u.x, _P); x3 = addmod(x3, _P - v.x, _P); uint256 y3 = addmod(u.x, _P - x3, _P); y3 = mulmod(y3, lam, _P); y3 = addmod(y3, _P - u.y, _P); return Point(x3, y3); } function checkIndividualSignature( bytes32 digest, bytes memory signature, uint8 signerIndex ) public view returns (bool) { address expectedAddress = getPubkeyAddress(signerIndex); address recovered = ECDSA.recover(digest, signature); return expectedAddress == recovered; } function requireValidTxSignatures( bytes calldata txn, uint64 idx, bytes[] calldata signatures ) public { bytes32 data = keccak256( abi.encodePacked(uint256(block.chainid), uint256(idx), txn) ); bytes32 hashedMsg = keccak256( abi.encodePacked("\x19Ethereum Signed Message:\n32", data) ); uint256 nSignatures = 0; for (uint256 i = 0; i < signatures.length; i++) { if (signatures[i].length > 0) { nSignatures += 1; require( checkIndividualSignature( hashedMsg, signatures[i], uint8(i) ), "invalid signature" ); } } require(nSignatures == nSigner, "not enough signatures"); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol"; import "./libraries/MathHelper.sol"; import "./interfaces/IEndpoint.sol"; import "./Verifier.sol"; import "./interfaces/engine/ISpotEngine.sol"; import "./interfaces/IERC20Base.sol"; import "./libraries/ERC20Helper.sol"; import "./common/Constants.sol"; contract WithdrawPool is EIP712Upgradeable, OwnableUpgradeable { using ERC20Helper for IERC20Base; using MathSD21x18 for int128; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize(address _clearinghouse, address _verifier) external initializer { __Ownable_init(); clearinghouse = _clearinghouse; verifier = _verifier; } address internal clearinghouse; address internal verifier; // submitted withdrawal idxs mapping(uint64 => bool) public markedIdxs; // collected withdrawal fees in native token decimals mapping(uint32 => int128) public fees; uint64 public minIdx; function submitFastWithdrawal( uint64 idx, bytes calldata transaction, bytes[] calldata signatures ) public { require(!markedIdxs[idx], "Withdrawal already submitted"); require(idx > minIdx, "idx too small"); markedIdxs[idx] = true; Verifier v = Verifier(verifier); v.requireValidTxSignatures(transaction, idx, signatures); IEndpoint.SignedWithdrawCollateral memory signedTx = abi.decode( transaction[1:], (IEndpoint.SignedWithdrawCollateral) ); IERC20Base token = getToken(signedTx.tx.productId); address sendTo = address(uint160(bytes20(signedTx.tx.sender))); uint128 transferAmount = signedTx.tx.amount; require(transferAmount <= INT128_MAX, ERR_CONVERSION_OVERFLOW); int128 fee = fastWithdrawalFeeAmount( token, signedTx.tx.productId, transferAmount ); require(transferAmount > uint128(fee), "Fee larger than balance"); transferAmount -= uint128(fee); fees[signedTx.tx.productId] += fee; handleWithdrawTransfer(token, sendTo, transferAmount); } function submitWithdrawal( IERC20Base token, address sendTo, uint128 amount, uint64 idx ) public { require(msg.sender == clearinghouse); if (markedIdxs[idx]) { return; } markedIdxs[idx] = true; // set minIdx to most recent withdrawal submitted by sequencer minIdx = idx; handleWithdrawTransfer(token, sendTo, amount); } function fastWithdrawalFeeAmount( IERC20Base token, uint32 productId, uint128 amount ) public view returns (int128) { uint8 decimals = token.decimals(); require(decimals <= MAX_DECIMALS); int256 multiplier = int256(10**(MAX_DECIMALS - uint8(decimals))); int128 amountX18 = int128(amount) * int128(multiplier); int128 proportionalFeeX18 = FAST_WITHDRAWAL_FEE_RATE.mul(amountX18); int128 minFeeX18 = 5 * spotEngine().getWithdrawFee(productId); int128 feeX18 = MathHelper.max(proportionalFeeX18, minFeeX18); return feeX18 / int128(multiplier); } function removeLiquidity( uint32 productId, uint128 amount, address sendTo ) external onlyOwner { handleWithdrawTransfer(getToken(productId), sendTo, amount); } function checkMarkedIdxs(uint64[] calldata idxs) public view returns (bool[] memory) { bool[] memory marked = new bool[](idxs.length); for (uint256 i = 0; i < idxs.length; i++) { marked[i] = markedIdxs[idxs[i]]; } return marked; } function checkProductBalances(uint32[] calldata productIds) public view returns (uint256[] memory) { uint256[] memory balances = new uint256[](productIds.length); for (uint256 i = 0; i < productIds.length; i++) { IERC20Base token = getToken(productIds[i]); balances[i] = token.balanceOf(address(this)); } return balances; } function handleWithdrawTransfer( IERC20Base token, address to, uint128 amount ) internal virtual { token.safeTransfer(to, uint256(amount)); } function safeTransferFrom( IERC20Base token, address from, uint256 amount ) internal virtual { token.safeTransferFrom(from, address(this), amount); } function getToken(uint32 productId) internal view returns (IERC20Base) { IERC20Base token = IERC20Base(spotEngine().getConfig(productId).token); require(address(token) != address(0)); return token; } function spotEngine() internal view returns (ISpotEngine) { return ISpotEngine( IClearinghouse(clearinghouse).getEngineByType( IProductEngine.EngineType.SPOT ) ); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; library console { address constant CONSOLE_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; function _sendLogPayloadImplementation(bytes memory payload) internal view { address consoleAddress = CONSOLE_ADDRESS; /// @solidity memory-safe-assembly assembly { pop( staticcall( gas(), consoleAddress, add(payload, 32), mload(payload), 0, 0 ) ) } } function _castToPure( function(bytes memory) internal view fnIn ) internal pure returns (function(bytes memory) pure fnOut) { assembly { fnOut := fnIn } } function _sendLogPayload(bytes memory payload) internal pure { _castToPure(_sendLogPayloadImplementation)(payload); } function log() internal pure { _sendLogPayload(abi.encodeWithSignature("log()")); } function logInt(int256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); } function logUint(uint256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); } function logString(string memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function logBool(bool p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function logAddress(address p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function logBytes(bytes memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); } function logBytes1(bytes1 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); } function logBytes2(bytes2 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); } function logBytes3(bytes3 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); } function logBytes4(bytes4 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); } function logBytes5(bytes5 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); } function logBytes6(bytes6 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); } function logBytes7(bytes7 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); } function logBytes8(bytes8 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); } function logBytes9(bytes9 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); } function logBytes10(bytes10 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); } function logBytes11(bytes11 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); } function logBytes12(bytes12 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); } function logBytes13(bytes13 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); } function logBytes14(bytes14 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); } function logBytes15(bytes15 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); } function logBytes16(bytes16 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); } function logBytes17(bytes17 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); } function logBytes18(bytes18 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); } function logBytes19(bytes19 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); } function logBytes20(bytes20 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); } function logBytes21(bytes21 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); } function logBytes22(bytes22 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); } function logBytes23(bytes23 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); } function logBytes24(bytes24 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); } function logBytes25(bytes25 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); } function logBytes26(bytes26 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); } function logBytes27(bytes27 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); } function logBytes28(bytes28 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); } function logBytes29(bytes29 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); } function logBytes30(bytes30 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); } function logBytes31(bytes31 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); } function logBytes32(bytes32 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); } function log(uint256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); } function log(string memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function log(bool p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function log(address p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function log(uint256 p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1)); } function log(uint256 p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1)); } function log(uint256 p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1)); } function log(uint256 p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1)); } function log(string memory p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); } function log(string memory p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); } function log(string memory p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); } function log(string memory p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); } function log(bool p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1)); } function log(bool p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); } function log(bool p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); } function log(bool p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); } function log(address p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1)); } function log(address p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); } function log(address p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); } function log(address p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); } function log(uint256 p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2)); } function log(uint256 p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2)); } function log(uint256 p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2)); } function log(uint256 p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2)); } function log(uint256 p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2)); } function log(uint256 p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2)); } function log(uint256 p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2)); } function log(uint256 p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2)); } function log(uint256 p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2)); } function log(uint256 p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2)); } function log(uint256 p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2)); } function log(uint256 p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2)); } function log(uint256 p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2)); } function log(string memory p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2)); } function log(string memory p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2)); } function log(string memory p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2)); } function log(string memory p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2)); } function log(string memory p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2)); } function log(string memory p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); } function log(string memory p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); } function log(string memory p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); } function log(string memory p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2)); } function log(string memory p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); } function log(string memory p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); } function log(string memory p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); } function log(string memory p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2)); } function log(string memory p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); } function log(string memory p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); } function log(string memory p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); } function log(bool p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2)); } function log(bool p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2)); } function log(bool p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2)); } function log(bool p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2)); } function log(bool p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2)); } function log(bool p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); } function log(bool p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); } function log(bool p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); } function log(bool p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2)); } function log(bool p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); } function log(bool p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); } function log(bool p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); } function log(bool p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2)); } function log(bool p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); } function log(bool p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); } function log(bool p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); } function log(address p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2)); } function log(address p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2)); } function log(address p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2)); } function log(address p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2)); } function log(address p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2)); } function log(address p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); } function log(address p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); } function log(address p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); } function log(address p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2)); } function log(address p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); } function log(address p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); } function log(address p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); } function log(address p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2)); } function log(address p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); } function log(address p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); } function log(address p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure { _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 pure { _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 pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure { _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 pure { _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 pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, string memory p3) internal pure { _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 pure { _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 pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure { _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 pure { _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 pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, string memory p3) internal pure { _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 pure { _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 pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure { _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 pure { _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 pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, string memory p3) internal pure { _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 pure { _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 pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); } }
// 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: 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; } } }
{ "optimizer": { "enabled": true, "runs": 800 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"endpoint","type":"address"},{"indexed":false,"internalType":"address","name":"quote","type":"address"}],"name":"ClearinghouseInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"liquidatorSubaccount","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"liquidateeSubaccount","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"productId","type":"uint32"},{"indexed":false,"internalType":"bool","name":"isEncodedSpread","type":"bool"},{"indexed":false,"internalType":"int128","name":"amount","type":"int128"},{"indexed":false,"internalType":"int128","name":"amountQuote","type":"int128"}],"name":"Liquidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int128","name":"amount","type":"int128"},{"indexed":true,"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"productId","type":"uint32"}],"name":"ModifyCollateral","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"},{"inputs":[{"internalType":"address","name":"engine","type":"address"},{"internalType":"address","name":"offchainExchange","type":"address"},{"internalType":"enum IProductEngine.EngineType","name":"engineType","type":"uint8"}],"name":"addEngine","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"transaction","type":"bytes"}],"name":"assertCode","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct IEndpoint.BurnLp","name":"txn","type":"tuple"}],"name":"burnLp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"bytes32","name":"recipient","type":"bytes32"}],"internalType":"struct IEndpoint.BurnLpAndTransfer","name":"txn","type":"tuple"}],"name":"burnLpAndTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"subaccount","type":"bytes32"}],"internalType":"struct IEndpoint.ClaimSequencerFees","name":"txn","type":"tuple"},{"internalType":"int128[]","name":"fees","type":"int128[]"}],"name":"claimSequencerFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"blastPoints","type":"address"},{"internalType":"address","name":"blast","type":"address"},{"internalType":"address","name":"gov","type":"address"}],"name":"configurePoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct IEndpoint.DepositCollateral","name":"txn","type":"tuple"}],"name":"depositCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"transaction","type":"bytes"}],"name":"depositInsurance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getClearinghouseLiq","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEndpoint","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getEngineByProduct","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IProductEngine.EngineType","name":"engineType","type":"uint8"}],"name":"getEngineByType","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"internalType":"enum IProductEngine.HealthType","name":"healthType","type":"uint8"}],"name":"getHealth","outputs":[{"internalType":"int128","name":"health","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInsurance","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getQuote","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSlowModeFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSpreads","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_endpoint","type":"address"},{"internalType":"address","name":"_quote","type":"address"},{"internalType":"address","name":"_clearinghouseLiq","type":"address"},{"internalType":"uint256","name":"_spreads","type":"uint256"},{"internalType":"address","name":"_withdrawPool","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"bytes32","name":"liquidatee","type":"bytes32"},{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"bool","name":"isEncodedSpread","type":"bool"},{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct IEndpoint.LiquidateSubaccount","name":"txn","type":"tuple"}],"name":"liquidateSubaccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"transaction","type":"bytes"}],"name":"manualAssert","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"uint128","name":"amountBase","type":"uint128"},{"internalType":"uint128","name":"quoteAmountLow","type":"uint128"},{"internalType":"uint128","name":"quoteAmountHigh","type":"uint128"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct IEndpoint.MintLp","name":"txn","type":"tuple"}],"name":"mintLp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"registerProduct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"requireMinDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_withdrawPool","type":"address"}],"name":"setWithdrawPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"transaction","type":"bytes"}],"name":"settlePnl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct IEndpoint.TransferQuote","name":"txn","type":"tuple"}],"name":"transferQuote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_clearinghouseLiq","type":"address"}],"name":"upgradeClearinghouseLiq","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"address","name":"sendTo","type":"address"},{"internalType":"uint64","name":"idx","type":"uint64"}],"name":"withdrawCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"transaction","type":"bytes"},{"internalType":"uint64","name":"idx","type":"uint64"}],"name":"withdrawInsurance","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50614e24806100206000396000f3fe608060405234801561001057600080fd5b506004361061020b5760003560e01c806388b6496f1161012a578063c227db96116100bd578063ed6185231161008c578063f16dec0611610071578063f16dec0614610478578063f2fde38b14610480578063fba560081461049357600080fd5b8063ed61852314610452578063f0390afe1461046557600080fd5b8063c227db96146103ea578063d693c5f1146103fd578063deb14ec314610410578063e671b16b1461043f57600080fd5b8063aed8e967116100f9578063aed8e967146103a0578063af9791d1146103b1578063bf11b3b1146103c4578063bf1fb321146103d757600080fd5b806388b6496f146103585780638da5cb5b1461036b5780639b0861c11461037c5780639eecee351461038d57600080fd5b8063530b97a4116101a257806367b9f60a1161017157806367b9f60a146103175780636dd0ef101461032a578063715018a61461033d5780638762d4221461034557600080fd5b8063530b97a4146102cb57806356e49ef3146102de5780635d2e9ad1146102f1578063672717221461030457600080fd5b80631d97d22f116101de5780631d97d22f14610278578063267a8da01461028b5780633c54c2de146102a557806352efadf1146102b857600080fd5b80630748a2191461021057806307e6d12314610225578063171755b114610240578063184f535114610265575b600080fd5b61022361021e366004613b3a565b6104a4565b005b61022d6108fe565b6040519081526020015b60405180910390f35b6068546001600160a01b03165b6040516001600160a01b039091168152602001610237565b610223610273366004613b9f565b610a26565b610223610286366004613b3a565b610bcc565b606f54600f0b5b604051600f9190910b8152602001610237565b6102236102b3366004613bf6565b610fc6565b6102236102c6366004613c25565b6110c1565b6102236102d9366004613c41565b61122d565b6102236102ec366004613cb6565b6113e1565b61024d6102ff366004613d01565b61160f565b610223610312366004613d1e565b611658565b610223610325366004613d76565b6118c3565b610223610338366004613dd8565b611cf8565b610223611dc4565b610223610353366004613e18565b611dd8565b610292610366366004613e35565b611f07565b6033546001600160a01b031661024d565b606a546001600160a01b031661024d565b61022361039b366004613e69565b612300565b6065546001600160a01b031661024d565b6102236103bf366004613b9f565b61255a565b6102236103d2366004613b9f565b6126a0565b6102236103e5366004613b3a565b6127ca565b6102236103f8366004613bf6565b612942565b61022361040b366004613ebd565b61297f565b61024d61041e366004613e18565b63ffffffff166000908152606c60205260409020546001600160a01b031690565b61022361044d366004613c25565b612b0f565b610223610460366004613b9f565b612d61565b610223610473366004613ef2565b612e56565b60705461022d565b61022361048e366004613bf6565b613450565b6071546001600160a01b031661024d565b6065546001600160a01b031633146105045760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084015b60405180910390fd5b6040805180820190915260018152605560f81b60208201526269736f823562ffffff16036105455760405162461bcd60e51b81526004016104fb9190613fac565b506040805180820190915260018152605560f81b60208201526269736f606083013562ffffff160361058a5760405162461bcd60e51b81526004016104fb9190613fac565b506000808052606d6020908152600080516020614daf833981519152546001600160a01b031691606c916105c49060408601908601613e18565b63ffffffff1681526020810191909152604001600020546001600160a01b038281169116146105f257600080fd5b6000806001600160a01b03831663d98752ec6106146040870160208801613e18565b86356106266060890160408a01613ff5565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b604482015260640160408051808303816000875af1158015610679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069d919061401f565b90925090506001600160a01b03831663e0b0621f600086356106be85614064565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561070d57600080fd5b505af1158015610721573d6000803e3d6000fd5b505060405163e0b0621f60e01b81526000600482015260608701356024820152600f84900b60448201526001600160a01b038616925063e0b0621f9150606401600060405180830381600087803b15801561077b57600080fd5b505af115801561078f573d6000803e3d6000fd5b5050506001600160a01b038416905063e0b0621f6107b36040870160208801613e18565b86356107be86614064565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561080d57600080fd5b505af1158015610821573d6000803e3d6000fd5b5050506001600160a01b038416905063e0b0621f6108456040870160208801613e18565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260608701356024820152600f85900b60448201526064015b600060405180830381600087803b15801561089957600080fd5b505af11580156108ad573d6000803e3d6000fd5b505050506108be84600001356134e0565b604051806040016040528060028152602001610a6960f31b815250906108f75760405162461bcd60e51b81526004016104fb9190613fac565b5050505050565b6000808052606d602052600080516020614daf83398151915254604080516338d0dce360e21b81526004810184905290516001600160a01b03909216918391839163e343738c9160248082019260a0929091908290030181865afa15801561096a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098e919061411d565b60000151905060006006826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fa91906141b5565b610a0491906141d8565b610a0f90600a6142df565b9050610a1e81620f42406142ee565b935050505090565b6000610a35826001818661438e565b810190610a429190614447565b90508060200151518160000151511460405180604001604052806003815260200162434e4d60e81b81525090610a8b5760405162461bcd60e51b81526004016104fb9190613fac565b5060005b815151811015610bc6576000610acc7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103546001600160a01b031690565b6001600160a01b031663972b83a084600001518481518110610af057610af061459e565b60200260200101516040518263ffffffff1660e01b8152600401610b149190613fac565b602060405180830381865afa158015610b31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5591906145b4565b90508083602001518381518110610b6e57610b6e61459e565b60200260200101511460405180604001604052806003815260200162434e4d60e81b81525090610bb15760405162461bcd60e51b81526004016104fb9190613fac565b50508080610bbe906145cd565b915050610a8f565b50505050565b6065546001600160a01b03163314610c275760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b60016001607f1b03610c3f6060830160408401613ff5565b6001600160801b0316111560405180604001604052806002815260200161434f60f01b81525090610c835760405162461bcd60e51b81526004016104fb9190613fac565b506000610c966060830160408401613ff5565b60008052606d6020908152600080516020614daf833981519152546040805180820190915260018152605560f81b818401529293506001600160a01b0316919084356bffffffffffffffffffffffff19908116918601351614610d0c5760405162461bcd60e51b81526004016104fb9190613fac565b506000610d216065546001600160a01b031690565b6001600160a01b0316638f4f8ecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8291906145e6565b905062ffffff8435166269736f03610e42576040516313b56ddb60e01b8152843560048201526020850135906001600160a01b038316906313b56ddb90602401602060405180830381865afa158015610ddf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0391906145b4565b14604051806040016040528060018152602001605560f81b81525090610e3c5760405162461bcd60e51b81526004016104fb9190613fac565b50610f02565b62ffffff6020850135166269736f03610f0257604051630d15968b60e11b815284356004820152602085013560248201526001600160a01b03821690631a2b2d1690604401602060405180830381865afa158015610ea4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec89190614611565b604051806040016040528060018152602001605560f81b81525090610f005760405162461bcd60e51b81526004016104fb9190613fac565b505b6001600160a01b03821663e0b0621f60008635610f1e87614064565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b158015610f6d57600080fd5b505af1158015610f81573d6000803e3d6000fd5b505060405163e0b0621f60e01b81526000600482015260208701356024820152600f86900b60448201526001600160a01b038516925063e0b0621f915060640161087f565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103546001600160a01b03166001600160a01b0316635244cd6e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105291906145e6565b6001600160a01b0316336001600160a01b031614604051806040016040528060018152602001605560f81b8152509061109e5760405162461bcd60e51b81526004016104fb9190613fac565b50606a80546001600160a01b0319166001600160a01b0392909216919091179055565b6065546001600160a01b0316331461111c5760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b60007f73eedd1711e7346828a0e610b1a5a4bc2c13ab4688d9b0c034855fdddd1be4b6905060008183604051602401611155919061462e565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990941693909317909252606a54915190925060009182916001600160a01b03909116906111c09085906146a5565b600060405180830381855af49150503d80600081146111fb576040519150601f19603f3d011682016040523d82523d6000602084013e611200565b606091505b50915091508181906112255760405162461bcd60e51b81526004016104fb9190613fac565b505050505050565b600054610100900460ff161580801561124d5750600054600160ff909116105b806112675750303b158015611267575060005460ff166001145b6112d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016104fb565b6000805460ff1916600117905580156112fc576000805461ff0019166101001790555b6113046134f9565b61130d8661356c565b606880546001600160a01b03199081166001600160a01b038881169182179093556069805430908416179055606a805483168885161790556070869055607180549092168584161790915560408051928916835260208301919091527f85cbc94663dc3e10fe6f4fb22712d52d5939321301933ac1b1132d47023698bd910160405180910390a18015611225576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6113e9613596565b6000606d8183600181111561140057611400613fdf565b600181111561141157611411613fdf565b81526020810191909152604001600020546001600160a01b03161461143557600080fd5b6001600160a01b03831661144857600080fd5b606e8054600180820183556000929092527f9930d9ff0dee0ef5ca2f7710ea66b8f84dd0f5f5351ecffe72b952cd9db7142a6020820401805486938593601f166101000a60ff810219909216919084908111156114a7576114a7613fdf565b021790555080606d60008460018111156114c3576114c3613fdf565b60018111156114d4576114d4613fdf565b81526020810191909152604001600090812080546001600160a01b0319166001600160a01b03939093169290921790915582600181111561151757611517613fdf565b036115605760008052606c6020527f7febd347df14ea35c529e50fb2dd629d4a6226f5ccc893710fb466f8b83823fc80546001600160a01b0319166001600160a01b0383161790555b6068546001600160a01b0380831691631459457a91309187911661158c6065546001600160a01b031690565b6033546040516001600160e01b031960e088901b1681526001600160a01b039586166004820152938516602485015291841660448401528316606483015291909116608482015260a4015b600060405180830381600087803b1580156115f157600080fd5b505af1158015611605573d6000803e3d6000fd5b5050505050505050565b6000606d600083600181111561162757611627613fdf565b600181111561163857611638613fdf565b81526020810191909152604001600020546001600160a01b031692915050565b6065546001600160a01b031633146116b35760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6040805180820190915260018152605560f81b60208201526269736f823562ffffff16036116f45760405162461bcd60e51b81526004016104fb9190613fac565b5060016001607f1b0361170d6060830160408401613ff5565b6001600160801b0316111560405180604001604052806002815260200161434f60f01b815250906117515760405162461bcd60e51b81526004016104fb9190613fac565b506000808052606d6020908152600080516020614daf833981519152546001600160a01b031691906117929061178d9060408601908601613e18565b6135f0565b9050601260ff821611156117a557600080fd5b60006117b28260126141d8565b6117bd90600a6142df565b90506000816117d26060870160408801613ff5565b6117dc91906146c1565b90506001600160a01b03841663e0b0621f6117fd6040880160208901613e18565b60405160e083901b6001600160e01b031916815263ffffffff909116600482015287356024820152600f84900b6044820152606401600060405180830381600087803b15801561184c57600080fd5b505af1158015611860573d6000803e3d6000fd5b5050863591507ffe53084a731040f869d38b1dcd00fbbdbc14e10d7d739160559d77f5bc80cf0590508261189a6040890160208a01613e18565b60408051600f9390930b835263ffffffff90911660208301520160405180910390a25050505050565b6065546001600160a01b0316331461191e5760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6040805180820190915260018152605560f81b60208201526269736f62ffffff87160361195e5760405162461bcd60e51b81526004016104fb9190613fac565b50604080518082019091526002815261434f60f01b602082015260016001607f1b036001600160801b03851611156119a95760405162461bcd60e51b81526004016104fb9190613fac565b506000808052606d602052600080516020614daf83398151915254604080516338d0dce360e21b815263ffffffff8816600482015290516001600160a01b039092169291839163e343738c9160248083019260a09291908290030181865afa158015611a19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3d919061411d565b5190506001600160a01b038116611a5357600080fd5b60018714611a62578660601c93505b611a6e8185878661367a565b6000611a79876135f0565b611a849060126141d8565b611a8f90600a6142df565b9050600081611a9d88614064565b611aa791906146c1565b60405163e0b0621f60e01b815263ffffffff8a166004820152602481018b9052600f82900b60448201529091506001600160a01b0385169063e0b0621f90606401600060405180830381600087803b158015611b0257600080fd5b505af1158015611b16573d6000803e3d6000fd5b5050604051634ac8d8c160e01b815263ffffffff8b1660048201526001600160a01b0387169250634ac8d8c1915060240160006040518083038186803b158015611b5f57600080fd5b505afa158015611b73573d6000803e3d6000fd5b5060009250505060018a14611b89576000611b8c565b60025b90506000611b9a8b83611f07565b600f0b1215604051806040016040528060028152602001610a6960f31b81525090611bd85760405162461bcd60e51b81526004016104fb9190613fac565b508863ffffffff16609103611ca857604051637c1e148760e01b815263ffffffff8a166004820152602481018b90526000906001600160a01b03871690637c1e1487906044016040805180830381865afa158015611c3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5e919061475f565b905060008160000151600f0b1215604051806040016040528060028152602001610a6960f31b81525090611ca55760405162461bcd60e51b81526004016104fb9190613fac565b50505b60408051600f84900b815263ffffffff8b1660208201528b917ffe53084a731040f869d38b1dcd00fbbdbc14e10d7d739160559d77f5bc80cf05910160405180910390a250505050505050505050565b611d00613596565b6040516336b91f2b60e01b81526001600160a01b0382811660048301528416906336b91f2b90602401600060405180830381600087803b158015611d4357600080fd5b505af1158015611d57573d6000803e3d6000fd5b505060405163c8992e6160e01b81526001600160a01b038516925063c8992e619150611d8d9060029060019086906004016147b0565b600060405180830381600087803b158015611da757600080fd5b505af1158015611dbb573d6000803e3d6000fd5b50505050505050565b611dcc613596565b611dd660006136f6565b565b60003390506000816001600160a01b0316634604d19b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4191906147ed565b905033606d6000836001811115611e5a57611e5a613fdf565b6001811115611e6b57611e6b613fdf565b815260200190815260200160002060009054906101000a90046001600160a01b03166001600160a01b031614604051806040016040528060018152602001605560f81b81525090611ecf5760405162461bcd60e51b81526004016104fb9190613fac565b505063ffffffff919091166000908152606c6020526040902080546001600160a01b0319166001600160a01b03909216919091179055565b606d602052600080516020614daf83398151915254600160009081527fbb98d58f7e9fdb81be27aecd01537329fa27413effec04afc2f01e87a038c2ba5460405163438e848960e11b815291926001600160a01b0390811692911690829063871d091290611f7b908890889060040161480a565b602060405180830381865afa158015611f98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fbc9190614827565b92506f80000000000000000000000000000000600f84900b01611fe05750506122fa565b6070545b801561227b57604051638a1d43c960e01b8152601082901c9160ff8082169260089290921c16906000906001600160a01b03861690638a1d43c990612031908c9086908d90600401614844565b606060405180830381865afa15801561204e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207291906148c3565b8051909150600f0b60000361208957505050611fe4565b604051638a1d43c960e01b81526000906001600160a01b03881690638a1d43c9906120bc908d9088908e90600401614844565b606060405180830381865afa1580156120d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fd91906148c3565b8051909150600f0b15806121205750815181516000600f91820b81129290910b13145b1561212e5750505050611fe4565b6000808260000151600f0b131561215d5781518351612156919061215190614064565b613748565b9050612180565b81518351612174919061216f90614064565b613764565b61217d90614064565b90505b600060028460400151846040015161219891906148df565b6121a2919061492e565b90506000808460000151600f0b13156121f25760058560400151670de0b6b3a76400006121cf9190614983565b6121d9919061492e565b6121eb90670de0b6b3a7640000614983565b905061222b565b60058460400151670de0b6b3a764000061220c9190614983565b612216919061492e565b61222890670de0b6b3a7640000614983565b90505b6122636122388383614983565b61225a8760200151876020015161224f91906148df565b600f87900b90613779565b600f0b90613779565b61226d908c6148df565b9a5050505050505050611fe4565b60405163438e848960e11b81526001600160a01b0383169063871d0912906122a9908990899060040161480a565b602060405180830381865afa1580156122c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ea9190614827565b6122f490856148df565b93505050505b92915050565b6065546001600160a01b0316331461235b5760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b600061236a836001818761438e565b81019061237791906149d3565b8051604080518082019091526002815261434f60f01b602082015291925060016001607f1b036001600160801b0390911611156123c75760405162461bcd60e51b81526004016104fb9190613fac565b5060006123d460006135f0565b6123df9060126141d8565b6123ea90600a6142df565b905060008183600001516123fe91906146c1565b606f546040805180820190915260028152614e4960f01b6020820152919250600f90810b9083900b13156124455760405162461bcd60e51b81526004016104fb9190613fac565b50606f805482919060009061245e908490600f0b614983565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055506000606d600080600181111561249d5761249d613fdf565b60018111156124ae576124ae613fdf565b81526020810191909152604090810160009081205491516338d0dce360e21b8152600481018290526001600160a01b03909216925090829063e343738c9060240160a060405180830381865afa15801561250c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612530919061411d565b5190506001600160a01b03811661254657600080fd5b61160581866020015187600001518961367a565b6065546001600160a01b031633146125b55760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b60006125c4826001818661438e565b8101906125d19190614a06565b8051604080518082019091526002815261434f60f01b602082015291925060016001607f1b036001600160801b0390911611156126215760405162461bcd60e51b81526004016104fb9190613fac565b50600061262e60006135f0565b6126399060126141d8565b61264490600a6142df565b9050600081836000015161265891906146c1565b606f80549192508291600090612672908490600f0b6148df565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055505050505050565b60006126af826001818661438e565b8101906126bc9190614ab4565b606d602052600080516020614daf8339815191525460016000527fbb98d58f7e9fdb81be27aecd01537329fa27413effec04afc2f01e87a038c2ba548251604051639b6f762b60e01b81529394506001600160a01b039283169391909216918291639b6f762b9161272f91600401614ba7565b60006040518083038186803b15801561274757600080fd5b505afa15801561275b573d6000803e3d6000fd5b505050506020830151604080850151905163030972b560e41b81526001600160a01b038516926330972b509261279392600401614bba565b60006040518083038186803b1580156127ab57600080fd5b505afa1580156127bf573d6000803e3d6000fd5b505050505050505050565b6065546001600160a01b031633146128255760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6040805180820190915260018152605560f81b60208201526269736f823562ffffff16036128665760405162461bcd60e51b81526004016104fb9190613fac565b50606c600061287b6040840160208501613e18565b63ffffffff1681526020808201929092526040908101600020546001600160a01b03169163d98752ec916128b491908501908501613e18565b83356128c66060860160408701613ff5565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b604482015260640160408051808303816000875af1158015612919573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061293d919061401f565b505050565b61294a613596565b6001600160a01b03811661295d57600080fd5b607180546001600160a01b0319166001600160a01b0392909216919091179055565b604080518082019091526002815261434f60f01b602082015260016001607f1b036001600160801b03831611156129c95760405162461bcd60e51b81526004016104fb9190613fac565b5060006129d5836135f0565b9050601260ff821611156129e857600080fd5b60006129f58260126141d8565b612a0090600a6142df565b90506000612a0e84836146c1565b9050670de0b6b3a764000063ffffffff861615612aa4576065546001600160a01b0316604051631b47234360e11b815263ffffffff881660048201526001600160a01b03919091169063368e468690602401602060405180830381865afa158015612a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aa19190614827565b90505b612ab7670de0b6b3a764000060056146c1565b600f0b612ad08383600f0b61377990919063ffffffff16565b600f0b12156040518060400160405280600381526020016244545360e81b81525090611dbb5760405162461bcd60e51b81526004016104fb9190613fac565b6065546001600160a01b03163314612b6a5760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6040805180820190915260018152605560f81b60208201526269736f823562ffffff1603612bab5760405162461bcd60e51b81526004016104fb9190613fac565b506000612bbe6040830160208401613e18565b63ffffffff1603612bce57600080fd5b612bde6040820160208301613e18565b63ffffffff166091141560405180604001604052806002815260200161049560f41b81525090612c215760405162461bcd60e51b81526004016104fb9190613fac565b50606c6000612c366040840160208501613e18565b63ffffffff1681526020808201929092526040908101600020546001600160a01b0316916398de72fe91612c6f91908501908501613e18565b8335612c816060860160408701613ff5565b612c916080870160608801613ff5565b612ca160a0880160808901613ff5565b6040516001600160e01b031960e088901b16815263ffffffff9590951660048601526024850193909352600f91820b6044850152810b60648401520b608482015260a401600060405180830381600087803b158015612cff57600080fd5b505af1158015612d13573d6000803e3d6000fd5b50505050612d2481600001356134e0565b604051806040016040528060028152602001610a6960f31b81525090612d5d5760405162461bcd60e51b81526004016104fb9190613fac565b5050565b6065546001600160a01b03163314612dbc5760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6000612dcb826001818661438e565b810190612dd89190614be8565b905060005b8151516001600160801b0382161015610bc657612e468260000151826001600160801b031681518110612e1257612e1261459e565b60200260200101518360200151836001600160801b031681518110612e3957612e3961459e565b60200260200101516137f8565b612e4f81614cd1565b9050612ddd565b6065546001600160a01b03163314612eb15760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6040805180820190915260018152605560f81b60208201526269736f843562ffffff1603612ef25760405162461bcd60e51b81526004016104fb9190613fac565b50606d602052600080516020614daf83398151915254600160009081527fbb98d58f7e9fdb81be27aecd01537329fa27413effec04afc2f01e87a038c2ba54604080516347428e7b60e01b815290516001600160a01b0394851694909216929184916347428e7b91600480830192869291908290030181865afa158015612f7d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fa59190810190614cf7565b90506000826001600160a01b03166347428e7b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612fe7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261300f9190810190614cf7565b905060005b8251811015613239576000856001600160a01b0316637c1e14878584815181106130405761304061459e565b60209081029190910101516040516001600160e01b031960e084901b16815263ffffffff9091166004820152600060248201526044016040805180830381865afa158015613092573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b6919061475f565b9050856001600160a01b031663e0b0621f8584815181106130d9576130d961459e565b60200260200101518b6000013584600001518c8c888181106130fd576130fd61459e565b90506020020160208101906131129190614d91565b61311c91906148df565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561316b57600080fd5b505af115801561317f573d6000803e3d6000fd5b50505050856001600160a01b031663e0b0621f8584815181106131a4576131a461459e565b60200260200101516000801b84600001516131be90614064565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561320d57600080fd5b505af1158015613221573d6000803e3d6000fd5b50505050508080613231906145cd565b915050613014565b5060005b8151811015611605576000846001600160a01b0316637c1e14878484815181106132695761326961459e565b60209081029190910101516040516001600160e01b031960e084901b16815263ffffffff909116600482015260006024820152604401606060405180830381865afa1580156132bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e091906148c3565b9050846001600160a01b031663f8a42e518484815181106133035761330361459e565b6020908102919091018101518451918501516040516001600160e01b031960e086901b16815263ffffffff90921660048301528d356024830152600f92830b604483015290910b6064820152608401600060405180830381600087803b15801561336c57600080fd5b505af1158015613380573d6000803e3d6000fd5b50505050846001600160a01b031663f8a42e518484815181106133a5576133a561459e565b60200260200101516000801b84600001516133bf90614064565b85602001516133cd90614064565b6040516001600160e01b031960e087901b16815263ffffffff9490941660048501526024840192909252600f90810b60448401520b6064820152608401600060405180830381600087803b15801561342457600080fd5b505af1158015613438573d6000803e3d6000fd5b50505050508080613448906145cd565b91505061323d565b613458613596565b6001600160a01b0381166134d45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016104fb565b6134dd816136f6565b50565b6000806134ee836000611f07565b600f0b121592915050565b600054610100900460ff166135645760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104fb565b611dd66138fe565b613574613596565b606580546001600160a01b0319166001600160a01b0392909216919091179055565b6033546001600160a01b03163314611dd65760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104fb565b6000806135fc83613972565b90506001600160a01b03811661361157600080fd5b806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561364f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367391906141b5565b9392505050565b60715461369d906001600160a01b0386811691166001600160801b038516613a0c565b6071546040516334fb054160e01b81526001600160a01b03868116600483015285811660248301526001600160801b038516604483015267ffffffffffffffff84166064830152909116906334fb0541906084016115d7565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081600f0b83600f0b1261375d5781613673565b5090919050565b600081600f0b83600f0b1361375d5781613673565b6000670de0b6b3a7640000600f83810b9085900b02056f7fffffffffffffffffffffffffffffff1981128015906137b7575060016001607f1b038113155b6040518060400160405280600281526020016127a360f11b815250906137f05760405162461bcd60e51b81526004016104fb9190613fac565b509392505050565b60016000908152606d60209081527fbb98d58f7e9fdb81be27aecd01537329fa27413effec04afc2f01e87a038c2ba546040805163d6b0e0b560e01b8152600481018790526024810186905290516001600160a01b039092169392849263d6b0e0b5926044808201939291829003018187875af115801561387d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138a19190614827565b6000808052606d602052600080516020614daf8339815191525460405163e0b0621f60e01b8152600481019290925260248201879052600f83900b60448301529192506001600160a01b039091169063e0b0621f906064016115d7565b600054610100900460ff166139695760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104fb565b611dd6336136f6565b6000808052606d602052600080516020614daf83398151915254604080516338d0dce360e21b815263ffffffff8516600482015290516001600160a01b0390921691829163e343738c9160248083019260a09291908290030181865afa1580156139e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a04919061411d565b519392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b1790529151600092839290871691613a7d91906146a5565b6000604051808303816000865af19150503d8060008114613aba576040519150601f19603f3d011682016040523d82523d6000602084013e613abf565b606091505b5091509150818015613ae9575080511580613ae9575080806020019051810190613ae99190614611565b604051806040016040528060028152602001612a2360f11b815250906112255760405162461bcd60e51b81526004016104fb9190613fac565b600060808284031215613b3457600080fd5b50919050565b600060808284031215613b4c57600080fd5b6136738383613b22565b60008083601f840112613b6857600080fd5b50813567ffffffffffffffff811115613b8057600080fd5b602083019150836020828501011115613b9857600080fd5b9250929050565b60008060208385031215613bb257600080fd5b823567ffffffffffffffff811115613bc957600080fd5b613bd585828601613b56565b90969095509350505050565b6001600160a01b03811681146134dd57600080fd5b600060208284031215613c0857600080fd5b813561367381613be1565b600060c08284031215613b3457600080fd5b600060c08284031215613c3757600080fd5b6136738383613c13565b600080600080600060a08688031215613c5957600080fd5b8535613c6481613be1565b94506020860135613c7481613be1565b93506040860135613c8481613be1565b9250606086013591506080860135613c9b81613be1565b809150509295509295909350565b600281106134dd57600080fd5b600080600060608486031215613ccb57600080fd5b8335613cd681613be1565b92506020840135613ce681613be1565b91506040840135613cf681613ca9565b809150509250925092565b600060208284031215613d1357600080fd5b813561367381613ca9565b600060608284031215613b3457600080fd5b63ffffffff811681146134dd57600080fd5b80356001600160801b0381168114613d5957600080fd5b919050565b803567ffffffffffffffff81168114613d5957600080fd5b600080600080600060a08688031215613d8e57600080fd5b853594506020860135613da081613d30565b9350613dae60408701613d42565b92506060860135613dbe81613be1565b9150613dcc60808701613d5e565b90509295509295909350565b600080600060608486031215613ded57600080fd5b8335613df881613be1565b92506020840135613e0881613be1565b91506040840135613cf681613be1565b600060208284031215613e2a57600080fd5b813561367381613d30565b60008060408385031215613e4857600080fd5b82359150602083013560038110613e5e57600080fd5b809150509250929050565b600080600060408486031215613e7e57600080fd5b833567ffffffffffffffff811115613e9557600080fd5b613ea186828701613b56565b9094509250613eb4905060208501613d5e565b90509250925092565b60008060408385031215613ed057600080fd5b8235613edb81613d30565b9150613ee960208401613d42565b90509250929050565b60008060008385036040811215613f0857600080fd5b6020811215613f1657600080fd5b50839250602084013567ffffffffffffffff80821115613f3557600080fd5b818601915086601f830112613f4957600080fd5b813581811115613f5857600080fd5b8760208260051b8501011115613f6d57600080fd5b6020830194508093505050509250925092565b60005b83811015613f9b578181015183820152602001613f83565b83811115610bc65750506000910152565b6020815260008251806020840152613fcb816040850160208701613f80565b601f01601f19169190910160400192915050565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561400757600080fd5b61367382613d42565b80600f0b81146134dd57600080fd5b6000806040838503121561403257600080fd5b825161403d81614010565b6020840151909250613e5e81614010565b634e487b7160e01b600052601160045260246000fd5b600081600f0b60016001607f1b031981036140815761408161404e565b60000392915050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156140c3576140c361408a565b60405290565b6040516060810167ffffffffffffffff811182821017156140c3576140c361408a565b604051601f8201601f1916810167ffffffffffffffff811182821017156141155761411561408a565b604052919050565b600060a0828403121561412f57600080fd5b60405160a0810181811067ffffffffffffffff821117156141525761415261408a565b604052825161416081613be1565b8152602083015161417081614010565b6020820152604083015161418381614010565b6040820152606083015161419681614010565b606082015260808301516141a981614010565b60808201529392505050565b6000602082840312156141c757600080fd5b815160ff8116811461367357600080fd5b600060ff821660ff8416808210156141f2576141f261404e565b90039392505050565b600181815b8085111561423657816000190482111561421c5761421c61404e565b8085161561422957918102915b93841c9390800290614200565b509250929050565b60008261424d575060016122fa565b8161425a575060006122fa565b8160018114614270576002811461427a57614296565b60019150506122fa565b60ff84111561428b5761428b61404e565b50506001821b6122fa565b5060208310610133831016604e8410600b84101617156142b9575081810a6122fa565b6142c383836141fb565b80600019048211156142d7576142d761404e565b029392505050565b600061367360ff84168361423e565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561432f5761432f61404e565b600160ff1b600087128281168783058912161561434e5761434e61404e565b6000871292508782058712848416161561436a5761436a61404e565b878505871281841616156143805761438061404e565b505050929093029392505050565b6000808585111561439e57600080fd5b838611156143ab57600080fd5b5050820193919092039150565b600067ffffffffffffffff8211156143d2576143d261408a565b5060051b60200190565b600082601f8301126143ed57600080fd5b813560206144026143fd836143b8565b6140ec565b82815260059290921b8401810191818101908684111561442157600080fd5b8286015b8481101561443c5780358352918301918301614425565b509695505050505050565b6000602080838503121561445a57600080fd5b823567ffffffffffffffff8082111561447257600080fd5b8185019150604080838803121561448857600080fd5b6144906140a0565b83358381111561449f57600080fd5b8401601f810189136144b057600080fd5b80356144be6143fd826143b8565b81815260059190911b8201870190878101908b8311156144dd57600080fd5b8884015b83811015614567578035888111156144f95760008081fd5b8501603f81018e1361450b5760008081fd5b8a8101358981111561451f5761451f61408a565b614531601f8201601f19168d016140ec565b8181528f8a8385010111156145465760008081fd5b818a84018e83013760009181018d01919091528452509189019189016144e1565b5084525050508385013591508282111561458057600080fd5b61458c888386016143dc565b85820152809550505050505092915050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156145c657600080fd5b5051919050565b6000600182016145df576145df61404e565b5060010190565b6000602082840312156145f857600080fd5b815161367381613be1565b80151581146134dd57600080fd5b60006020828403121561462357600080fd5b815161367381614603565b813581526020808301359082015260c08101604083013561464e81613d30565b63ffffffff166040830152606083013561466781614603565b15156060830152608083013561467c81614010565b600f0b608083015267ffffffffffffffff61469960a08501613d5e565b1660a083015292915050565b600082516146b7818460208701613f80565b9190910192915050565b600081600f0b83600f0b60016001607f1b036000821360008413838304851182821616156146f1576146f161404e565b6f7fffffffffffffffffffffffffffffff19600085128281168783058712161561471d5761471d61404e565b600087129250858205871284841616156147395761473961404e565b8585058712818416161561474f5761474f61404e565b5050509290910295945050505050565b60006040828403121561477157600080fd5b6147796140a0565b825161478481614010565b8152602083015161479481614010565b60208201529392505050565b600381106134dd576134dd613fdf565b606081016147bd856147a0565b848252600284106147d0576147d0613fdf565b8360208301526001600160a01b0383166040830152949350505050565b6000602082840312156147ff57600080fd5b815161367381613ca9565b8281526040810161481a836147a0565b8260208301529392505050565b60006020828403121561483957600080fd5b815161367381614010565b83815263ffffffff8316602082015260608101614860836147a0565b826040830152949350505050565b60006060828403121561488057600080fd5b6148886140c9565b9050815161489581614010565b815260208201516148a581614010565b602082015260408201516148b881614010565b604082015292915050565b6000606082840312156148d557600080fd5b613673838361486e565b600081600f0b83600f0b600082128260016001607f1b03038213811516156149095761490961404e565b8260016001607f1b03190382128116156149255761492561404e565b50019392505050565b600081600f0b83600f0b8061495357634e487b7160e01b600052601260045260246000fd5b6f7fffffffffffffffffffffffffffffff1982146000198214161561497a5761497a61404e565b90059392505050565b600081600f0b83600f0b600081128160016001607f1b0319018312811516156149ae576149ae61404e565b8160016001607f1b030183138116156149c9576149c961404e565b5090039392505050565b6000604082840312156149e557600080fd5b6149ed6140a0565b6149f683613d42565b8152602083013561479481613be1565b600060208284031215614a1857600080fd5b6040516020810181811067ffffffffffffffff82111715614a3b57614a3b61408a565b604052614a4783613d42565b81529392505050565b600082601f830112614a6157600080fd5b81356020614a716143fd836143b8565b82815260059290921b84018101918181019086841115614a9057600080fd5b8286015b8481101561443c578035614aa781614010565b8352918301918301614a94565b600060208284031215614ac657600080fd5b813567ffffffffffffffff80821115614ade57600080fd5b9083019060608286031215614af257600080fd5b614afa6140c9565b823582811115614b0957600080fd5b614b1587828601614a50565b825250602083013582811115614b2a57600080fd5b614b3687828601614a50565b602083015250604083013582811115614b4e57600080fd5b614b5a87828601614a50565b60408301525095945050505050565b600081518084526020808501945080840160005b83811015614b9c578151600f0b87529582019590820190600101614b7d565b509495945050505050565b6020815260006136736020830184614b69565b604081526000614bcd6040830185614b69565b8281036020840152614bdf8185614b69565b95945050505050565b60006020808385031215614bfb57600080fd5b823567ffffffffffffffff80821115614c1357600080fd5b9084019060408287031215614c2757600080fd5b614c2f6140a0565b823582811115614c3e57600080fd5b614c4a888286016143dc565b8252508383013582811115614c5e57600080fd5b80840193505086601f840112614c7357600080fd5b82359150614c836143fd836143b8565b82815260059290921b83018401918481019088841115614ca257600080fd5b938501935b83851015614cc057843582529385019390850190614ca7565b948201949094529695505050505050565b60006001600160801b03808316818103614ced57614ced61404e565b6001019392505050565b60006020808385031215614d0a57600080fd5b825167ffffffffffffffff811115614d2157600080fd5b8301601f81018513614d3257600080fd5b8051614d406143fd826143b8565b81815260059190911b82018301908381019087831115614d5f57600080fd5b928401925b82841015614d86578351614d7781613d30565b82529284019290840190614d64565b979650505050505050565b600060208284031215614da357600080fd5b81356136738161401056feda90043ba5b4096ba14704bc227ab0d3167da15b887e62ab2e76e37daa71135653657175656e63657247617465643a2063616c6c6572206973206e6f74207468a2646970667358221220a3304a04136887ae91bb39fee76310ed3be8ac67ee1586bf0b82c5d4dadd683464736f6c634300080d0033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061020b5760003560e01c806388b6496f1161012a578063c227db96116100bd578063ed6185231161008c578063f16dec0611610071578063f16dec0614610478578063f2fde38b14610480578063fba560081461049357600080fd5b8063ed61852314610452578063f0390afe1461046557600080fd5b8063c227db96146103ea578063d693c5f1146103fd578063deb14ec314610410578063e671b16b1461043f57600080fd5b8063aed8e967116100f9578063aed8e967146103a0578063af9791d1146103b1578063bf11b3b1146103c4578063bf1fb321146103d757600080fd5b806388b6496f146103585780638da5cb5b1461036b5780639b0861c11461037c5780639eecee351461038d57600080fd5b8063530b97a4116101a257806367b9f60a1161017157806367b9f60a146103175780636dd0ef101461032a578063715018a61461033d5780638762d4221461034557600080fd5b8063530b97a4146102cb57806356e49ef3146102de5780635d2e9ad1146102f1578063672717221461030457600080fd5b80631d97d22f116101de5780631d97d22f14610278578063267a8da01461028b5780633c54c2de146102a557806352efadf1146102b857600080fd5b80630748a2191461021057806307e6d12314610225578063171755b114610240578063184f535114610265575b600080fd5b61022361021e366004613b3a565b6104a4565b005b61022d6108fe565b6040519081526020015b60405180910390f35b6068546001600160a01b03165b6040516001600160a01b039091168152602001610237565b610223610273366004613b9f565b610a26565b610223610286366004613b3a565b610bcc565b606f54600f0b5b604051600f9190910b8152602001610237565b6102236102b3366004613bf6565b610fc6565b6102236102c6366004613c25565b6110c1565b6102236102d9366004613c41565b61122d565b6102236102ec366004613cb6565b6113e1565b61024d6102ff366004613d01565b61160f565b610223610312366004613d1e565b611658565b610223610325366004613d76565b6118c3565b610223610338366004613dd8565b611cf8565b610223611dc4565b610223610353366004613e18565b611dd8565b610292610366366004613e35565b611f07565b6033546001600160a01b031661024d565b606a546001600160a01b031661024d565b61022361039b366004613e69565b612300565b6065546001600160a01b031661024d565b6102236103bf366004613b9f565b61255a565b6102236103d2366004613b9f565b6126a0565b6102236103e5366004613b3a565b6127ca565b6102236103f8366004613bf6565b612942565b61022361040b366004613ebd565b61297f565b61024d61041e366004613e18565b63ffffffff166000908152606c60205260409020546001600160a01b031690565b61022361044d366004613c25565b612b0f565b610223610460366004613b9f565b612d61565b610223610473366004613ef2565b612e56565b60705461022d565b61022361048e366004613bf6565b613450565b6071546001600160a01b031661024d565b6065546001600160a01b031633146105045760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084015b60405180910390fd5b6040805180820190915260018152605560f81b60208201526269736f823562ffffff16036105455760405162461bcd60e51b81526004016104fb9190613fac565b506040805180820190915260018152605560f81b60208201526269736f606083013562ffffff160361058a5760405162461bcd60e51b81526004016104fb9190613fac565b506000808052606d6020908152600080516020614daf833981519152546001600160a01b031691606c916105c49060408601908601613e18565b63ffffffff1681526020810191909152604001600020546001600160a01b038281169116146105f257600080fd5b6000806001600160a01b03831663d98752ec6106146040870160208801613e18565b86356106266060890160408a01613ff5565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b604482015260640160408051808303816000875af1158015610679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069d919061401f565b90925090506001600160a01b03831663e0b0621f600086356106be85614064565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561070d57600080fd5b505af1158015610721573d6000803e3d6000fd5b505060405163e0b0621f60e01b81526000600482015260608701356024820152600f84900b60448201526001600160a01b038616925063e0b0621f9150606401600060405180830381600087803b15801561077b57600080fd5b505af115801561078f573d6000803e3d6000fd5b5050506001600160a01b038416905063e0b0621f6107b36040870160208801613e18565b86356107be86614064565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561080d57600080fd5b505af1158015610821573d6000803e3d6000fd5b5050506001600160a01b038416905063e0b0621f6108456040870160208801613e18565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260608701356024820152600f85900b60448201526064015b600060405180830381600087803b15801561089957600080fd5b505af11580156108ad573d6000803e3d6000fd5b505050506108be84600001356134e0565b604051806040016040528060028152602001610a6960f31b815250906108f75760405162461bcd60e51b81526004016104fb9190613fac565b5050505050565b6000808052606d602052600080516020614daf83398151915254604080516338d0dce360e21b81526004810184905290516001600160a01b03909216918391839163e343738c9160248082019260a0929091908290030181865afa15801561096a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098e919061411d565b60000151905060006006826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fa91906141b5565b610a0491906141d8565b610a0f90600a6142df565b9050610a1e81620f42406142ee565b935050505090565b6000610a35826001818661438e565b810190610a429190614447565b90508060200151518160000151511460405180604001604052806003815260200162434e4d60e81b81525090610a8b5760405162461bcd60e51b81526004016104fb9190613fac565b5060005b815151811015610bc6576000610acc7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103546001600160a01b031690565b6001600160a01b031663972b83a084600001518481518110610af057610af061459e565b60200260200101516040518263ffffffff1660e01b8152600401610b149190613fac565b602060405180830381865afa158015610b31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5591906145b4565b90508083602001518381518110610b6e57610b6e61459e565b60200260200101511460405180604001604052806003815260200162434e4d60e81b81525090610bb15760405162461bcd60e51b81526004016104fb9190613fac565b50508080610bbe906145cd565b915050610a8f565b50505050565b6065546001600160a01b03163314610c275760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b60016001607f1b03610c3f6060830160408401613ff5565b6001600160801b0316111560405180604001604052806002815260200161434f60f01b81525090610c835760405162461bcd60e51b81526004016104fb9190613fac565b506000610c966060830160408401613ff5565b60008052606d6020908152600080516020614daf833981519152546040805180820190915260018152605560f81b818401529293506001600160a01b0316919084356bffffffffffffffffffffffff19908116918601351614610d0c5760405162461bcd60e51b81526004016104fb9190613fac565b506000610d216065546001600160a01b031690565b6001600160a01b0316638f4f8ecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8291906145e6565b905062ffffff8435166269736f03610e42576040516313b56ddb60e01b8152843560048201526020850135906001600160a01b038316906313b56ddb90602401602060405180830381865afa158015610ddf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0391906145b4565b14604051806040016040528060018152602001605560f81b81525090610e3c5760405162461bcd60e51b81526004016104fb9190613fac565b50610f02565b62ffffff6020850135166269736f03610f0257604051630d15968b60e11b815284356004820152602085013560248201526001600160a01b03821690631a2b2d1690604401602060405180830381865afa158015610ea4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec89190614611565b604051806040016040528060018152602001605560f81b81525090610f005760405162461bcd60e51b81526004016104fb9190613fac565b505b6001600160a01b03821663e0b0621f60008635610f1e87614064565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b158015610f6d57600080fd5b505af1158015610f81573d6000803e3d6000fd5b505060405163e0b0621f60e01b81526000600482015260208701356024820152600f86900b60448201526001600160a01b038516925063e0b0621f915060640161087f565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103546001600160a01b03166001600160a01b0316635244cd6e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105291906145e6565b6001600160a01b0316336001600160a01b031614604051806040016040528060018152602001605560f81b8152509061109e5760405162461bcd60e51b81526004016104fb9190613fac565b50606a80546001600160a01b0319166001600160a01b0392909216919091179055565b6065546001600160a01b0316331461111c5760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b60007f73eedd1711e7346828a0e610b1a5a4bc2c13ab4688d9b0c034855fdddd1be4b6905060008183604051602401611155919061462e565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990941693909317909252606a54915190925060009182916001600160a01b03909116906111c09085906146a5565b600060405180830381855af49150503d80600081146111fb576040519150601f19603f3d011682016040523d82523d6000602084013e611200565b606091505b50915091508181906112255760405162461bcd60e51b81526004016104fb9190613fac565b505050505050565b600054610100900460ff161580801561124d5750600054600160ff909116105b806112675750303b158015611267575060005460ff166001145b6112d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016104fb565b6000805460ff1916600117905580156112fc576000805461ff0019166101001790555b6113046134f9565b61130d8661356c565b606880546001600160a01b03199081166001600160a01b038881169182179093556069805430908416179055606a805483168885161790556070869055607180549092168584161790915560408051928916835260208301919091527f85cbc94663dc3e10fe6f4fb22712d52d5939321301933ac1b1132d47023698bd910160405180910390a18015611225576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6113e9613596565b6000606d8183600181111561140057611400613fdf565b600181111561141157611411613fdf565b81526020810191909152604001600020546001600160a01b03161461143557600080fd5b6001600160a01b03831661144857600080fd5b606e8054600180820183556000929092527f9930d9ff0dee0ef5ca2f7710ea66b8f84dd0f5f5351ecffe72b952cd9db7142a6020820401805486938593601f166101000a60ff810219909216919084908111156114a7576114a7613fdf565b021790555080606d60008460018111156114c3576114c3613fdf565b60018111156114d4576114d4613fdf565b81526020810191909152604001600090812080546001600160a01b0319166001600160a01b03939093169290921790915582600181111561151757611517613fdf565b036115605760008052606c6020527f7febd347df14ea35c529e50fb2dd629d4a6226f5ccc893710fb466f8b83823fc80546001600160a01b0319166001600160a01b0383161790555b6068546001600160a01b0380831691631459457a91309187911661158c6065546001600160a01b031690565b6033546040516001600160e01b031960e088901b1681526001600160a01b039586166004820152938516602485015291841660448401528316606483015291909116608482015260a4015b600060405180830381600087803b1580156115f157600080fd5b505af1158015611605573d6000803e3d6000fd5b5050505050505050565b6000606d600083600181111561162757611627613fdf565b600181111561163857611638613fdf565b81526020810191909152604001600020546001600160a01b031692915050565b6065546001600160a01b031633146116b35760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6040805180820190915260018152605560f81b60208201526269736f823562ffffff16036116f45760405162461bcd60e51b81526004016104fb9190613fac565b5060016001607f1b0361170d6060830160408401613ff5565b6001600160801b0316111560405180604001604052806002815260200161434f60f01b815250906117515760405162461bcd60e51b81526004016104fb9190613fac565b506000808052606d6020908152600080516020614daf833981519152546001600160a01b031691906117929061178d9060408601908601613e18565b6135f0565b9050601260ff821611156117a557600080fd5b60006117b28260126141d8565b6117bd90600a6142df565b90506000816117d26060870160408801613ff5565b6117dc91906146c1565b90506001600160a01b03841663e0b0621f6117fd6040880160208901613e18565b60405160e083901b6001600160e01b031916815263ffffffff909116600482015287356024820152600f84900b6044820152606401600060405180830381600087803b15801561184c57600080fd5b505af1158015611860573d6000803e3d6000fd5b5050863591507ffe53084a731040f869d38b1dcd00fbbdbc14e10d7d739160559d77f5bc80cf0590508261189a6040890160208a01613e18565b60408051600f9390930b835263ffffffff90911660208301520160405180910390a25050505050565b6065546001600160a01b0316331461191e5760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6040805180820190915260018152605560f81b60208201526269736f62ffffff87160361195e5760405162461bcd60e51b81526004016104fb9190613fac565b50604080518082019091526002815261434f60f01b602082015260016001607f1b036001600160801b03851611156119a95760405162461bcd60e51b81526004016104fb9190613fac565b506000808052606d602052600080516020614daf83398151915254604080516338d0dce360e21b815263ffffffff8816600482015290516001600160a01b039092169291839163e343738c9160248083019260a09291908290030181865afa158015611a19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3d919061411d565b5190506001600160a01b038116611a5357600080fd5b60018714611a62578660601c93505b611a6e8185878661367a565b6000611a79876135f0565b611a849060126141d8565b611a8f90600a6142df565b9050600081611a9d88614064565b611aa791906146c1565b60405163e0b0621f60e01b815263ffffffff8a166004820152602481018b9052600f82900b60448201529091506001600160a01b0385169063e0b0621f90606401600060405180830381600087803b158015611b0257600080fd5b505af1158015611b16573d6000803e3d6000fd5b5050604051634ac8d8c160e01b815263ffffffff8b1660048201526001600160a01b0387169250634ac8d8c1915060240160006040518083038186803b158015611b5f57600080fd5b505afa158015611b73573d6000803e3d6000fd5b5060009250505060018a14611b89576000611b8c565b60025b90506000611b9a8b83611f07565b600f0b1215604051806040016040528060028152602001610a6960f31b81525090611bd85760405162461bcd60e51b81526004016104fb9190613fac565b508863ffffffff16609103611ca857604051637c1e148760e01b815263ffffffff8a166004820152602481018b90526000906001600160a01b03871690637c1e1487906044016040805180830381865afa158015611c3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5e919061475f565b905060008160000151600f0b1215604051806040016040528060028152602001610a6960f31b81525090611ca55760405162461bcd60e51b81526004016104fb9190613fac565b50505b60408051600f84900b815263ffffffff8b1660208201528b917ffe53084a731040f869d38b1dcd00fbbdbc14e10d7d739160559d77f5bc80cf05910160405180910390a250505050505050505050565b611d00613596565b6040516336b91f2b60e01b81526001600160a01b0382811660048301528416906336b91f2b90602401600060405180830381600087803b158015611d4357600080fd5b505af1158015611d57573d6000803e3d6000fd5b505060405163c8992e6160e01b81526001600160a01b038516925063c8992e619150611d8d9060029060019086906004016147b0565b600060405180830381600087803b158015611da757600080fd5b505af1158015611dbb573d6000803e3d6000fd5b50505050505050565b611dcc613596565b611dd660006136f6565b565b60003390506000816001600160a01b0316634604d19b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4191906147ed565b905033606d6000836001811115611e5a57611e5a613fdf565b6001811115611e6b57611e6b613fdf565b815260200190815260200160002060009054906101000a90046001600160a01b03166001600160a01b031614604051806040016040528060018152602001605560f81b81525090611ecf5760405162461bcd60e51b81526004016104fb9190613fac565b505063ffffffff919091166000908152606c6020526040902080546001600160a01b0319166001600160a01b03909216919091179055565b606d602052600080516020614daf83398151915254600160009081527fbb98d58f7e9fdb81be27aecd01537329fa27413effec04afc2f01e87a038c2ba5460405163438e848960e11b815291926001600160a01b0390811692911690829063871d091290611f7b908890889060040161480a565b602060405180830381865afa158015611f98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fbc9190614827565b92506f80000000000000000000000000000000600f84900b01611fe05750506122fa565b6070545b801561227b57604051638a1d43c960e01b8152601082901c9160ff8082169260089290921c16906000906001600160a01b03861690638a1d43c990612031908c9086908d90600401614844565b606060405180830381865afa15801561204e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207291906148c3565b8051909150600f0b60000361208957505050611fe4565b604051638a1d43c960e01b81526000906001600160a01b03881690638a1d43c9906120bc908d9088908e90600401614844565b606060405180830381865afa1580156120d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fd91906148c3565b8051909150600f0b15806121205750815181516000600f91820b81129290910b13145b1561212e5750505050611fe4565b6000808260000151600f0b131561215d5781518351612156919061215190614064565b613748565b9050612180565b81518351612174919061216f90614064565b613764565b61217d90614064565b90505b600060028460400151846040015161219891906148df565b6121a2919061492e565b90506000808460000151600f0b13156121f25760058560400151670de0b6b3a76400006121cf9190614983565b6121d9919061492e565b6121eb90670de0b6b3a7640000614983565b905061222b565b60058460400151670de0b6b3a764000061220c9190614983565b612216919061492e565b61222890670de0b6b3a7640000614983565b90505b6122636122388383614983565b61225a8760200151876020015161224f91906148df565b600f87900b90613779565b600f0b90613779565b61226d908c6148df565b9a5050505050505050611fe4565b60405163438e848960e11b81526001600160a01b0383169063871d0912906122a9908990899060040161480a565b602060405180830381865afa1580156122c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ea9190614827565b6122f490856148df565b93505050505b92915050565b6065546001600160a01b0316331461235b5760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b600061236a836001818761438e565b81019061237791906149d3565b8051604080518082019091526002815261434f60f01b602082015291925060016001607f1b036001600160801b0390911611156123c75760405162461bcd60e51b81526004016104fb9190613fac565b5060006123d460006135f0565b6123df9060126141d8565b6123ea90600a6142df565b905060008183600001516123fe91906146c1565b606f546040805180820190915260028152614e4960f01b6020820152919250600f90810b9083900b13156124455760405162461bcd60e51b81526004016104fb9190613fac565b50606f805482919060009061245e908490600f0b614983565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055506000606d600080600181111561249d5761249d613fdf565b60018111156124ae576124ae613fdf565b81526020810191909152604090810160009081205491516338d0dce360e21b8152600481018290526001600160a01b03909216925090829063e343738c9060240160a060405180830381865afa15801561250c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612530919061411d565b5190506001600160a01b03811661254657600080fd5b61160581866020015187600001518961367a565b6065546001600160a01b031633146125b55760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b60006125c4826001818661438e565b8101906125d19190614a06565b8051604080518082019091526002815261434f60f01b602082015291925060016001607f1b036001600160801b0390911611156126215760405162461bcd60e51b81526004016104fb9190613fac565b50600061262e60006135f0565b6126399060126141d8565b61264490600a6142df565b9050600081836000015161265891906146c1565b606f80549192508291600090612672908490600f0b6148df565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055505050505050565b60006126af826001818661438e565b8101906126bc9190614ab4565b606d602052600080516020614daf8339815191525460016000527fbb98d58f7e9fdb81be27aecd01537329fa27413effec04afc2f01e87a038c2ba548251604051639b6f762b60e01b81529394506001600160a01b039283169391909216918291639b6f762b9161272f91600401614ba7565b60006040518083038186803b15801561274757600080fd5b505afa15801561275b573d6000803e3d6000fd5b505050506020830151604080850151905163030972b560e41b81526001600160a01b038516926330972b509261279392600401614bba565b60006040518083038186803b1580156127ab57600080fd5b505afa1580156127bf573d6000803e3d6000fd5b505050505050505050565b6065546001600160a01b031633146128255760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6040805180820190915260018152605560f81b60208201526269736f823562ffffff16036128665760405162461bcd60e51b81526004016104fb9190613fac565b50606c600061287b6040840160208501613e18565b63ffffffff1681526020808201929092526040908101600020546001600160a01b03169163d98752ec916128b491908501908501613e18565b83356128c66060860160408701613ff5565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b604482015260640160408051808303816000875af1158015612919573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061293d919061401f565b505050565b61294a613596565b6001600160a01b03811661295d57600080fd5b607180546001600160a01b0319166001600160a01b0392909216919091179055565b604080518082019091526002815261434f60f01b602082015260016001607f1b036001600160801b03831611156129c95760405162461bcd60e51b81526004016104fb9190613fac565b5060006129d5836135f0565b9050601260ff821611156129e857600080fd5b60006129f58260126141d8565b612a0090600a6142df565b90506000612a0e84836146c1565b9050670de0b6b3a764000063ffffffff861615612aa4576065546001600160a01b0316604051631b47234360e11b815263ffffffff881660048201526001600160a01b03919091169063368e468690602401602060405180830381865afa158015612a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aa19190614827565b90505b612ab7670de0b6b3a764000060056146c1565b600f0b612ad08383600f0b61377990919063ffffffff16565b600f0b12156040518060400160405280600381526020016244545360e81b81525090611dbb5760405162461bcd60e51b81526004016104fb9190613fac565b6065546001600160a01b03163314612b6a5760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6040805180820190915260018152605560f81b60208201526269736f823562ffffff1603612bab5760405162461bcd60e51b81526004016104fb9190613fac565b506000612bbe6040830160208401613e18565b63ffffffff1603612bce57600080fd5b612bde6040820160208301613e18565b63ffffffff166091141560405180604001604052806002815260200161049560f41b81525090612c215760405162461bcd60e51b81526004016104fb9190613fac565b50606c6000612c366040840160208501613e18565b63ffffffff1681526020808201929092526040908101600020546001600160a01b0316916398de72fe91612c6f91908501908501613e18565b8335612c816060860160408701613ff5565b612c916080870160608801613ff5565b612ca160a0880160808901613ff5565b6040516001600160e01b031960e088901b16815263ffffffff9590951660048601526024850193909352600f91820b6044850152810b60648401520b608482015260a401600060405180830381600087803b158015612cff57600080fd5b505af1158015612d13573d6000803e3d6000fd5b50505050612d2481600001356134e0565b604051806040016040528060028152602001610a6960f31b81525090612d5d5760405162461bcd60e51b81526004016104fb9190613fac565b5050565b6065546001600160a01b03163314612dbc5760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6000612dcb826001818661438e565b810190612dd89190614be8565b905060005b8151516001600160801b0382161015610bc657612e468260000151826001600160801b031681518110612e1257612e1261459e565b60200260200101518360200151836001600160801b031681518110612e3957612e3961459e565b60200260200101516137f8565b612e4f81614cd1565b9050612ddd565b6065546001600160a01b03163314612eb15760405162461bcd60e51b815260206004820152602a6024820152600080516020614dcf8339815191526044820152691948195b991c1bda5b9d60b21b60648201526084016104fb565b6040805180820190915260018152605560f81b60208201526269736f843562ffffff1603612ef25760405162461bcd60e51b81526004016104fb9190613fac565b50606d602052600080516020614daf83398151915254600160009081527fbb98d58f7e9fdb81be27aecd01537329fa27413effec04afc2f01e87a038c2ba54604080516347428e7b60e01b815290516001600160a01b0394851694909216929184916347428e7b91600480830192869291908290030181865afa158015612f7d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fa59190810190614cf7565b90506000826001600160a01b03166347428e7b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612fe7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261300f9190810190614cf7565b905060005b8251811015613239576000856001600160a01b0316637c1e14878584815181106130405761304061459e565b60209081029190910101516040516001600160e01b031960e084901b16815263ffffffff9091166004820152600060248201526044016040805180830381865afa158015613092573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b6919061475f565b9050856001600160a01b031663e0b0621f8584815181106130d9576130d961459e565b60200260200101518b6000013584600001518c8c888181106130fd576130fd61459e565b90506020020160208101906131129190614d91565b61311c91906148df565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561316b57600080fd5b505af115801561317f573d6000803e3d6000fd5b50505050856001600160a01b031663e0b0621f8584815181106131a4576131a461459e565b60200260200101516000801b84600001516131be90614064565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561320d57600080fd5b505af1158015613221573d6000803e3d6000fd5b50505050508080613231906145cd565b915050613014565b5060005b8151811015611605576000846001600160a01b0316637c1e14878484815181106132695761326961459e565b60209081029190910101516040516001600160e01b031960e084901b16815263ffffffff909116600482015260006024820152604401606060405180830381865afa1580156132bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e091906148c3565b9050846001600160a01b031663f8a42e518484815181106133035761330361459e565b6020908102919091018101518451918501516040516001600160e01b031960e086901b16815263ffffffff90921660048301528d356024830152600f92830b604483015290910b6064820152608401600060405180830381600087803b15801561336c57600080fd5b505af1158015613380573d6000803e3d6000fd5b50505050846001600160a01b031663f8a42e518484815181106133a5576133a561459e565b60200260200101516000801b84600001516133bf90614064565b85602001516133cd90614064565b6040516001600160e01b031960e087901b16815263ffffffff9490941660048501526024840192909252600f90810b60448401520b6064820152608401600060405180830381600087803b15801561342457600080fd5b505af1158015613438573d6000803e3d6000fd5b50505050508080613448906145cd565b91505061323d565b613458613596565b6001600160a01b0381166134d45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016104fb565b6134dd816136f6565b50565b6000806134ee836000611f07565b600f0b121592915050565b600054610100900460ff166135645760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104fb565b611dd66138fe565b613574613596565b606580546001600160a01b0319166001600160a01b0392909216919091179055565b6033546001600160a01b03163314611dd65760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104fb565b6000806135fc83613972565b90506001600160a01b03811661361157600080fd5b806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561364f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367391906141b5565b9392505050565b60715461369d906001600160a01b0386811691166001600160801b038516613a0c565b6071546040516334fb054160e01b81526001600160a01b03868116600483015285811660248301526001600160801b038516604483015267ffffffffffffffff84166064830152909116906334fb0541906084016115d7565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081600f0b83600f0b1261375d5781613673565b5090919050565b600081600f0b83600f0b1361375d5781613673565b6000670de0b6b3a7640000600f83810b9085900b02056f7fffffffffffffffffffffffffffffff1981128015906137b7575060016001607f1b038113155b6040518060400160405280600281526020016127a360f11b815250906137f05760405162461bcd60e51b81526004016104fb9190613fac565b509392505050565b60016000908152606d60209081527fbb98d58f7e9fdb81be27aecd01537329fa27413effec04afc2f01e87a038c2ba546040805163d6b0e0b560e01b8152600481018790526024810186905290516001600160a01b039092169392849263d6b0e0b5926044808201939291829003018187875af115801561387d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138a19190614827565b6000808052606d602052600080516020614daf8339815191525460405163e0b0621f60e01b8152600481019290925260248201879052600f83900b60448301529192506001600160a01b039091169063e0b0621f906064016115d7565b600054610100900460ff166139695760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104fb565b611dd6336136f6565b6000808052606d602052600080516020614daf83398151915254604080516338d0dce360e21b815263ffffffff8516600482015290516001600160a01b0390921691829163e343738c9160248083019260a09291908290030181865afa1580156139e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a04919061411d565b519392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b1790529151600092839290871691613a7d91906146a5565b6000604051808303816000865af19150503d8060008114613aba576040519150601f19603f3d011682016040523d82523d6000602084013e613abf565b606091505b5091509150818015613ae9575080511580613ae9575080806020019051810190613ae99190614611565b604051806040016040528060028152602001612a2360f11b815250906112255760405162461bcd60e51b81526004016104fb9190613fac565b600060808284031215613b3457600080fd5b50919050565b600060808284031215613b4c57600080fd5b6136738383613b22565b60008083601f840112613b6857600080fd5b50813567ffffffffffffffff811115613b8057600080fd5b602083019150836020828501011115613b9857600080fd5b9250929050565b60008060208385031215613bb257600080fd5b823567ffffffffffffffff811115613bc957600080fd5b613bd585828601613b56565b90969095509350505050565b6001600160a01b03811681146134dd57600080fd5b600060208284031215613c0857600080fd5b813561367381613be1565b600060c08284031215613b3457600080fd5b600060c08284031215613c3757600080fd5b6136738383613c13565b600080600080600060a08688031215613c5957600080fd5b8535613c6481613be1565b94506020860135613c7481613be1565b93506040860135613c8481613be1565b9250606086013591506080860135613c9b81613be1565b809150509295509295909350565b600281106134dd57600080fd5b600080600060608486031215613ccb57600080fd5b8335613cd681613be1565b92506020840135613ce681613be1565b91506040840135613cf681613ca9565b809150509250925092565b600060208284031215613d1357600080fd5b813561367381613ca9565b600060608284031215613b3457600080fd5b63ffffffff811681146134dd57600080fd5b80356001600160801b0381168114613d5957600080fd5b919050565b803567ffffffffffffffff81168114613d5957600080fd5b600080600080600060a08688031215613d8e57600080fd5b853594506020860135613da081613d30565b9350613dae60408701613d42565b92506060860135613dbe81613be1565b9150613dcc60808701613d5e565b90509295509295909350565b600080600060608486031215613ded57600080fd5b8335613df881613be1565b92506020840135613e0881613be1565b91506040840135613cf681613be1565b600060208284031215613e2a57600080fd5b813561367381613d30565b60008060408385031215613e4857600080fd5b82359150602083013560038110613e5e57600080fd5b809150509250929050565b600080600060408486031215613e7e57600080fd5b833567ffffffffffffffff811115613e9557600080fd5b613ea186828701613b56565b9094509250613eb4905060208501613d5e565b90509250925092565b60008060408385031215613ed057600080fd5b8235613edb81613d30565b9150613ee960208401613d42565b90509250929050565b60008060008385036040811215613f0857600080fd5b6020811215613f1657600080fd5b50839250602084013567ffffffffffffffff80821115613f3557600080fd5b818601915086601f830112613f4957600080fd5b813581811115613f5857600080fd5b8760208260051b8501011115613f6d57600080fd5b6020830194508093505050509250925092565b60005b83811015613f9b578181015183820152602001613f83565b83811115610bc65750506000910152565b6020815260008251806020840152613fcb816040850160208701613f80565b601f01601f19169190910160400192915050565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561400757600080fd5b61367382613d42565b80600f0b81146134dd57600080fd5b6000806040838503121561403257600080fd5b825161403d81614010565b6020840151909250613e5e81614010565b634e487b7160e01b600052601160045260246000fd5b600081600f0b60016001607f1b031981036140815761408161404e565b60000392915050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156140c3576140c361408a565b60405290565b6040516060810167ffffffffffffffff811182821017156140c3576140c361408a565b604051601f8201601f1916810167ffffffffffffffff811182821017156141155761411561408a565b604052919050565b600060a0828403121561412f57600080fd5b60405160a0810181811067ffffffffffffffff821117156141525761415261408a565b604052825161416081613be1565b8152602083015161417081614010565b6020820152604083015161418381614010565b6040820152606083015161419681614010565b606082015260808301516141a981614010565b60808201529392505050565b6000602082840312156141c757600080fd5b815160ff8116811461367357600080fd5b600060ff821660ff8416808210156141f2576141f261404e565b90039392505050565b600181815b8085111561423657816000190482111561421c5761421c61404e565b8085161561422957918102915b93841c9390800290614200565b509250929050565b60008261424d575060016122fa565b8161425a575060006122fa565b8160018114614270576002811461427a57614296565b60019150506122fa565b60ff84111561428b5761428b61404e565b50506001821b6122fa565b5060208310610133831016604e8410600b84101617156142b9575081810a6122fa565b6142c383836141fb565b80600019048211156142d7576142d761404e565b029392505050565b600061367360ff84168361423e565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561432f5761432f61404e565b600160ff1b600087128281168783058912161561434e5761434e61404e565b6000871292508782058712848416161561436a5761436a61404e565b878505871281841616156143805761438061404e565b505050929093029392505050565b6000808585111561439e57600080fd5b838611156143ab57600080fd5b5050820193919092039150565b600067ffffffffffffffff8211156143d2576143d261408a565b5060051b60200190565b600082601f8301126143ed57600080fd5b813560206144026143fd836143b8565b6140ec565b82815260059290921b8401810191818101908684111561442157600080fd5b8286015b8481101561443c5780358352918301918301614425565b509695505050505050565b6000602080838503121561445a57600080fd5b823567ffffffffffffffff8082111561447257600080fd5b8185019150604080838803121561448857600080fd5b6144906140a0565b83358381111561449f57600080fd5b8401601f810189136144b057600080fd5b80356144be6143fd826143b8565b81815260059190911b8201870190878101908b8311156144dd57600080fd5b8884015b83811015614567578035888111156144f95760008081fd5b8501603f81018e1361450b5760008081fd5b8a8101358981111561451f5761451f61408a565b614531601f8201601f19168d016140ec565b8181528f8a8385010111156145465760008081fd5b818a84018e83013760009181018d01919091528452509189019189016144e1565b5084525050508385013591508282111561458057600080fd5b61458c888386016143dc565b85820152809550505050505092915050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156145c657600080fd5b5051919050565b6000600182016145df576145df61404e565b5060010190565b6000602082840312156145f857600080fd5b815161367381613be1565b80151581146134dd57600080fd5b60006020828403121561462357600080fd5b815161367381614603565b813581526020808301359082015260c08101604083013561464e81613d30565b63ffffffff166040830152606083013561466781614603565b15156060830152608083013561467c81614010565b600f0b608083015267ffffffffffffffff61469960a08501613d5e565b1660a083015292915050565b600082516146b7818460208701613f80565b9190910192915050565b600081600f0b83600f0b60016001607f1b036000821360008413838304851182821616156146f1576146f161404e565b6f7fffffffffffffffffffffffffffffff19600085128281168783058712161561471d5761471d61404e565b600087129250858205871284841616156147395761473961404e565b8585058712818416161561474f5761474f61404e565b5050509290910295945050505050565b60006040828403121561477157600080fd5b6147796140a0565b825161478481614010565b8152602083015161479481614010565b60208201529392505050565b600381106134dd576134dd613fdf565b606081016147bd856147a0565b848252600284106147d0576147d0613fdf565b8360208301526001600160a01b0383166040830152949350505050565b6000602082840312156147ff57600080fd5b815161367381613ca9565b8281526040810161481a836147a0565b8260208301529392505050565b60006020828403121561483957600080fd5b815161367381614010565b83815263ffffffff8316602082015260608101614860836147a0565b826040830152949350505050565b60006060828403121561488057600080fd5b6148886140c9565b9050815161489581614010565b815260208201516148a581614010565b602082015260408201516148b881614010565b604082015292915050565b6000606082840312156148d557600080fd5b613673838361486e565b600081600f0b83600f0b600082128260016001607f1b03038213811516156149095761490961404e565b8260016001607f1b03190382128116156149255761492561404e565b50019392505050565b600081600f0b83600f0b8061495357634e487b7160e01b600052601260045260246000fd5b6f7fffffffffffffffffffffffffffffff1982146000198214161561497a5761497a61404e565b90059392505050565b600081600f0b83600f0b600081128160016001607f1b0319018312811516156149ae576149ae61404e565b8160016001607f1b030183138116156149c9576149c961404e565b5090039392505050565b6000604082840312156149e557600080fd5b6149ed6140a0565b6149f683613d42565b8152602083013561479481613be1565b600060208284031215614a1857600080fd5b6040516020810181811067ffffffffffffffff82111715614a3b57614a3b61408a565b604052614a4783613d42565b81529392505050565b600082601f830112614a6157600080fd5b81356020614a716143fd836143b8565b82815260059290921b84018101918181019086841115614a9057600080fd5b8286015b8481101561443c578035614aa781614010565b8352918301918301614a94565b600060208284031215614ac657600080fd5b813567ffffffffffffffff80821115614ade57600080fd5b9083019060608286031215614af257600080fd5b614afa6140c9565b823582811115614b0957600080fd5b614b1587828601614a50565b825250602083013582811115614b2a57600080fd5b614b3687828601614a50565b602083015250604083013582811115614b4e57600080fd5b614b5a87828601614a50565b60408301525095945050505050565b600081518084526020808501945080840160005b83811015614b9c578151600f0b87529582019590820190600101614b7d565b509495945050505050565b6020815260006136736020830184614b69565b604081526000614bcd6040830185614b69565b8281036020840152614bdf8185614b69565b95945050505050565b60006020808385031215614bfb57600080fd5b823567ffffffffffffffff80821115614c1357600080fd5b9084019060408287031215614c2757600080fd5b614c2f6140a0565b823582811115614c3e57600080fd5b614c4a888286016143dc565b8252508383013582811115614c5e57600080fd5b80840193505086601f840112614c7357600080fd5b82359150614c836143fd836143b8565b82815260059290921b83018401918481019088841115614ca257600080fd5b938501935b83851015614cc057843582529385019390850190614ca7565b948201949094529695505050505050565b60006001600160801b03808316818103614ced57614ced61404e565b6001019392505050565b60006020808385031215614d0a57600080fd5b825167ffffffffffffffff811115614d2157600080fd5b8301601f81018513614d3257600080fd5b8051614d406143fd826143b8565b81815260059190911b82018301908381019087831115614d5f57600080fd5b928401925b82841015614d86578351614d7781613d30565b82529284019290840190614d64565b979650505050505050565b600060208284031215614da357600080fd5b81356136738161401056feda90043ba5b4096ba14704bc227ab0d3167da15b887e62ab2e76e37daa71135653657175656e63657247617465643a2063616c6c6572206973206e6f74207468a2646970667358221220a3304a04136887ae91bb39fee76310ed3be8ac67ee1586bf0b82c5d4dadd683464736f6c634300080d0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.