Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
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 Source Code Verified (Exact Match)
Contract Name:
ExchangeWithGenericSwap
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 1 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "./ExchangeWithAtomic.sol"; import "./libs/LibGenericSwap.sol"; import "./interfaces/IAggregationExecutor.sol"; contract ExchangeWithGenericSwap is ExchangeWithAtomic { using SafeERC20 for IERC20; using SafeTransferHelper for IERC20; error InsufficientBalance(); error ZeroReturnAmount(); /// @notice Fills user's limit order through pools, delegating all calls encoded in `data` to `executor`. See tests for usage examples /// @param order User signed limit order /// @param executor Aggregation executor that executes calls described in `data` /// @param desc Swap description /// @param data Encoded calls that `caller` should execute in between of swaps function fillThroughPools( uint112 filledAmount, LibValidator.Order calldata order, IAggregationExecutor executor, LibValidator.SwapDescription memory desc, bytes calldata permit, bytes calldata data ) external onlyMatcher nonReentrant { bytes32 orderHash = LibValidator.checkOrderSingleMatch(order, desc, filledAmount, block.timestamp); // if destination token is equal to fee token then fee will be fully paid inside executor contract if (address(desc.dstToken) != order.matcherFeeAsset) { payMatcherFee(order); } else { desc.minReturnAmount -= order.matcherFee; // condition desc.minReturnAmount > order.matcher fee was checked in LibValidator } LibGenericSwap.transferToInitialSource(order.senderAddress, desc, permit, assetBalances, liabilities); LibGenericSwap.fillThroughPools(orderHash, order.senderAddress, executor, desc, data); updateFilledAmount(orderHash, order.amount, filledAmount); } /// @notice Performs a swap, delegating all calls encoded in `data` to `executor`. See tests for usage examples /// @param executor Aggregation executor that executes calls described in `data` /// @param desc Swap description /// @param data Encoded calls that `caller` should execute in between of swaps /// @return returnAmount Resulting token amount /// @return spentAmount Source token amount /// @return gasLeft Gas left function swap( IAggregationExecutor executor, LibValidator.SwapDescription memory desc, bytes calldata permit, bytes calldata data ) public payable nonReentrant returns (uint256 returnAmount, uint256 spentAmount, uint256 gasLeft) { if (desc.minReturnAmount == 0) revert ZeroReturnAmount(); LibGenericSwap.transferToInitialSource(msg.sender, desc, permit, assetBalances, liabilities); (returnAmount, spentAmount, gasLeft) = LibGenericSwap.swap(msg.sender, executor, desc, data); } function payMatcherFee(LibValidator.Order memory order) internal { LibExchange._updateBalance( order.senderAddress, order.matcherFeeAsset, -int(uint(order.matcherFee)), assetBalances, liabilities ); if (assetBalances[order.senderAddress][order.matcherFeeAsset] < 0) revert InsufficientBalance(); LibExchange._updateBalance( order.matcherAddress, order.matcherFeeAsset, int(uint(order.matcherFee)), assetBalances, liabilities ); } }
// 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.1) (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 Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library 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 v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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.9.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to * 0 before setting it to a non-zero value. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (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 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @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 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 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 256, 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 << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol) pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler * now has built in overflow checking. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a % b; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.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 `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @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); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./libs/LibUnitConverter.sol"; import "./libs/LibValidator.sol"; import "./libs/LibExchange.sol"; import "./libs/MarginalFunctionality.sol"; import "./libs/SafeTransferHelper.sol"; import "./OrionVault.sol"; /** * @title Exchange * @dev Exchange contract for the Orion Protocol * @author @wafflemakr */ /* Overflow safety: We do not use SafeMath and control overflows by not accepting large ints on input. Balances inside contract are stored as int192. Allowed input amounts are int112 or uint112: it is enough for all practically used tokens: for instance if decimal unit is 1e18, int112 allow to encode up to 2.5e15 decimal units. That way adding/subtracting any amount from balances won't overflow, since minimum number of operations to reach max int is practically infinite: ~1e24. Allowed prices are uint64. Note, that price is represented as price per 1e8 tokens. That means that amount*price always fit uint256, while amount*price/1e8 not only fit int192, but also can be added, subtracted without overflow checks: number of malicious operations to overflow ~1e13. */ contract Exchange is OrionVault { using LibValidator for LibValidator.Order; using SafeERC20 for IERC20; struct UpdateOrderBalanceData { uint buyType; uint sellType; int buyIn; int sellIn; } // Flags for updateOrders // All flags are explicit uint8 constant kSell = 0; uint8 constant kBuy = 1; // if 0 - then sell uint8 constant kCorrectMatcherFeeByOrderAmount = 2; // EVENTS event NewAssetTransaction( address indexed beneficiary, address indexed recipient, address indexed assetAddress, bool isDeposit, uint112 amount, uint64 timestamp ); event Trade( address indexed buyer, address indexed seller, address baseAsset, address quoteAsset, uint64 filledPrice, uint192 filledAmount, uint192 amountQuote, bytes32 tradeId ); error IncorrectPosition(); error OnlyMatcher(); error AlreadyFilled(); error Fallback(); error Overflow(); error EthDepositRejected(); error NotCollateralAsset(); modifier onlyMatcher() { if (msg.sender != _allowedMatcher) revert OnlyMatcher(); _; } // MAIN FUNCTIONS /** * @dev Since Exchange will work behind the Proxy contract it can not have constructor */ function initialize() public payable initializer { OwnableUpgradeable.__Ownable_init(); } /** * @dev set marginal settings * @param _collateralAssets - list of addresses of assets which may be used as collateral * @param _stakeRisk - risk coefficient for staked orion as uint8 (0=0, 255=1) * @param _liquidationPremium - premium for liquidator as uint8 (0=0, 255=1) * @param _priceOverdue - time after that price became outdated * @param _positionOverdue - time after that liabilities became overdue and may be liquidated */ function updateMarginalSettings( address[] calldata _collateralAssets, uint8 _stakeRisk, uint8 _liquidationPremium, uint64 _priceOverdue, uint64 _positionOverdue ) public onlyOwner { collateralAssets = _collateralAssets; stakeRisk = _stakeRisk; liquidationPremium = _liquidationPremium; priceOverdue = _priceOverdue; positionOverdue = _positionOverdue; } /** * @dev set risk coefficients for collateral assets * @param assets - list of assets * @param risks - list of risks as uint8 (0=0, 255=1) */ function updateAssetRisks(address[] calldata assets, uint8[] calldata risks) public onlyOwner { for (uint256 i; i < assets.length; i++) assetRisks[assets[i]] = risks[i]; } /** * @dev Deposit ERC20 tokens to the exchange contract. Beneficiary is msg.sender * @dev User needs to approve token contract first * @param amount asset amount to deposit in its base unit */ function depositAsset(address assetAddress, uint112 amount) external { depositAssetTo(assetAddress, amount, msg.sender); } /** * @dev Deposit ERC20 tokens to the exchange contract. Beneficiary is account * @dev User needs to approve token contract first * @param amount asset amount to deposit in its base unit */ function depositAssetTo(address assetAddress, uint112 amount, address account) public nonReentrant { uint256 actualAmount = IERC20(assetAddress).balanceOf(address(this)); IERC20(assetAddress).safeTransferFrom(msg.sender, address(this), uint256(amount)); actualAmount = IERC20(assetAddress).balanceOf(address(this)) - actualAmount; if (actualAmount < amount) revert NotEnoughBalance(); generalDeposit(assetAddress, uint112(actualAmount), account); } /** * @notice Deposit ETH to the exchange contract. Beneficiary is msg.sender * @dev deposit event will be emitted with the amount in decimal format (10^8) * @dev balance will be stored in decimal format too */ function deposit() external payable { depositTo(msg.sender); } /** * @notice Deposit ETH to the exchange contract. Beneficiary is account * @dev deposit event will be emitted with the amount in decimal format (10^8) * @dev balance will be stored in decimal format too */ function depositTo(address account) public payable nonReentrant { generalDeposit(address(0), uint112(msg.value), account); } /** * @dev internal implementation of deposits */ function generalDeposit(address assetAddress, uint112 amount, address account) internal { bool wasLiability = assetBalances[account][assetAddress] < 0; uint112 safeAmountDecimal = LibUnitConverter.baseUnitToDecimal(assetAddress, amount); assetBalances[account][assetAddress] += int192(uint192(safeAmountDecimal)); emit LibExchange.BalanceChange(account, assetAddress, int192(uint192(safeAmountDecimal))); if (amount > 0) emit NewAssetTransaction(msg.sender, account, assetAddress, true, safeAmountDecimal, uint64(block.timestamp)); if (wasLiability) MarginalFunctionality.updateLiability( account, assetAddress, liabilities, uint112(safeAmountDecimal), assetBalances[account][assetAddress] ); } /** * @dev Withdrawal of funds from the contract to provided address * @param assetAddress address of the asset to withdraw * @param amount asset amount to withdraw in its base unit * @param to recipient address */ function withdrawTo(address assetAddress, uint112 amount, address to) public nonReentrant { uint112 safeAmountDecimal = LibUnitConverter.baseUnitToDecimal(assetAddress, amount); assetBalances[msg.sender][assetAddress] -= int192(uint192(safeAmountDecimal)); emit LibExchange.BalanceChange(to, assetAddress, -int192(uint192(safeAmountDecimal))); if (assetBalances[msg.sender][assetAddress] < 0) revert NotEnoughBalance(); if (!checkPosition(to)) revert IncorrectPosition(); if (assetAddress == address(0)) { (bool success, ) = to.call{value: amount}(""); if (!success) revert NotEnoughBalance(); } else { IERC20(assetAddress).safeTransfer(to, amount); } emit NewAssetTransaction(msg.sender, to, assetAddress, false, safeAmountDecimal, uint64(block.timestamp)); } /** * @dev Withdrawal of remaining funds from the contract to the address * @param assetAddress address of the asset to withdraw * @param amount asset amount to withdraw in its base unit */ function withdraw(address assetAddress, uint112 amount) external { withdrawTo(assetAddress, amount, msg.sender); } /** * @dev Get asset balance for a specific address * @param assetAddress address of the asset to query * @param user user address to query */ function getBalance(address assetAddress, address user) public view returns (int192) { return assetBalances[user][assetAddress]; } /** * @dev Batch query of asset balances for a user * @param assetsAddresses array of addresses of the assets to query * @param user user address to query */ function getBalances( address[] memory assetsAddresses, address user ) public view returns (int192[] memory balances) { balances = new int192[](assetsAddresses.length); for (uint256 i; i < assetsAddresses.length; i++) { balances[i] = assetBalances[user][assetsAddresses[i]]; } } /** * @dev Batch query of asset liabilities for a user * @param user user address to query */ function getLiabilities( address user ) public view returns (MarginalFunctionality.Liability[] memory liabilitiesArray) { return liabilities[user]; } /** * @dev Return list of assets which can be used for collateral */ function getCollateralAssets() public view returns (address[] memory) { return collateralAssets; } /** * @dev get filled amounts for a specific order */ function getFilledAmounts( bytes32 orderHash, LibValidator.Order memory order ) public view returns (int192 totalFilled, int192 totalFeesPaid) { totalFilled = int192(filledAmounts[orderHash]); //It is safe to convert here: filledAmounts is result of ui112 additions totalFeesPaid = int192( uint192((uint256(order.matcherFee) * uint256(uint192(totalFilled))) / uint256(order.amount)) ); //matcherFee is u64; safe multiplication here } function updateFilledAmount(bytes32 orderHash, uint192 amount, uint112 filledBase) internal { uint192 total_amount = filledAmounts[orderHash]; total_amount += filledBase; //it is safe to add ui112 to each other to get i192 if (total_amount > amount) revert AlreadyFilled(); filledAmounts[orderHash] = total_amount; } /** * @notice Settle a trade with two orders, filled price and amount * @dev 2 orders are submitted, it is necessary to match them: check conditions in orders for compliance filledPrice, filledAmount change balances on the contract respectively with buyer, seller, matcher * @param buyOrder structure of buy side order * @param sellOrder structure of sell side order * @param filledPrice price at which the order was settled * @param filledAmount amount settled between orders */ function fillOrders( LibValidator.Order memory buyOrder, LibValidator.Order memory sellOrder, uint64 filledPrice, uint112 filledAmount ) public nonReentrant { // --- VARIABLES --- // // Amount of quote asset uint256 _amountQuote = (uint256(filledAmount) * filledPrice) / (10 ** 8); if (_amountQuote >= type(uint112).max) revert Overflow(); uint112 amountQuote = uint112(_amountQuote); // --- VALIDATIONS --- // // Validate signatures using eth typed sign V1 (bytes32 buyOrderHash, bytes32 sellOrderHash) = LibValidator.checkOrdersInfo( buyOrder, sellOrder, msg.sender, filledAmount, filledPrice, block.timestamp, _allowedMatcher ); // --- UPDATES --- // //updateFilledAmount updateFilledAmount(buyOrderHash, buyOrder.amount, filledAmount); updateFilledAmount(sellOrderHash, sellOrder.amount, filledAmount); // Update User's balances UpdateOrderBalanceData memory data; (data.buyType, data.buyIn) = LibExchange.updateOrderBalanceDebit( buyOrder, filledAmount, amountQuote, kBuy | kCorrectMatcherFeeByOrderAmount, assetBalances, liabilities ); (data.sellType, data.sellIn) = LibExchange.updateOrderBalanceDebit( sellOrder, filledAmount, amountQuote, kSell | kCorrectMatcherFeeByOrderAmount, assetBalances, liabilities ); LibExchange.creditUserAssets( data.buyType, buyOrder.senderAddress, data.buyIn, buyOrder.baseAsset, assetBalances, liabilities ); LibExchange.creditUserAssets( data.sellType, sellOrder.senderAddress, data.sellIn, sellOrder.quoteAsset, assetBalances, liabilities ); if (!checkPosition(buyOrder.senderAddress)) revert IncorrectPosition(); if (!checkPosition(sellOrder.senderAddress)) revert IncorrectPosition(); emit Trade( buyOrder.senderAddress, sellOrder.senderAddress, buyOrder.baseAsset, buyOrder.quoteAsset, filledPrice, filledAmount, amountQuote, keccak256(abi.encode(buyOrderHash, sellOrderHash)) ); } /** * @dev wrapper for LibValidator methods, may be deleted. */ function validateOrder(LibValidator.Order memory order) public pure returns (bool isValid) { (isValid, ) = LibValidator.validateV3(order); } /** * @dev check user marginal position (compare assets and liabilities) * @return isPositive - boolean whether liabilities are covered by collateral or not */ function checkPosition(address user) public view returns (bool) { if (liabilities[user].length == 0) return true; return calcPosition(user).state == MarginalFunctionality.PositionState.POSITIVE; } /** * @dev internal methods which collect all variables used by MarginalFunctionality to one structure * @param user user address to query * @return UsedConstants - MarginalFunctionality.UsedConstants structure */ function getConstants(address user) internal view returns (MarginalFunctionality.UsedConstants memory) { return MarginalFunctionality.UsedConstants( user, _oracleAddress, address(_orionToken), positionOverdue, priceOverdue, stakeRisk, liquidationPremium ); } /** * @dev calc user marginal position (compare assets and liabilities) * @param user user address to query * @return position - MarginalFunctionality.Position structure */ function calcPosition(address user) public view returns (MarginalFunctionality.Position memory) { MarginalFunctionality.UsedConstants memory constants = getConstants(user); return MarginalFunctionality.calcPosition(collateralAssets, liabilities, assetBalances, assetRisks, constants); } /** * @dev method to cover some of overdue broker liabilities and get ORN in exchange same as liquidation or margin call * @param broker - broker which will be liquidated * @param redeemedAsset - asset, liability of which will be covered * @param collateralAsset - asset, with which liability will be covered * @param amount - amount of covered asset */ function partiallyLiquidate(address broker, address redeemedAsset, address collateralAsset, uint112 amount) public { bool isCollateralAsset = false; for (uint i = 0; i < collateralAssets.length; ++i) { if (collateralAssets[i] == collateralAsset) { isCollateralAsset = true; break; } } if (!isCollateralAsset) revert NotCollateralAsset(); MarginalFunctionality.UsedConstants memory constants = getConstants(broker); MarginalFunctionality.partiallyLiquidate( collateralAssets, liabilities, assetBalances, assetRisks, constants, redeemedAsset, collateralAsset, amount ); } receive() external payable { if (msg.sender == tx.origin) revert EthDepositRejected(); } /** * @dev revert on fallback function */ fallback() external { revert Fallback(); } /* Error Codes E1: Insufficient Balance, flavor S - stake, L - liabilities, P - Position, B,S - buyer, seller E2: Invalid Signature, flavor B,S - buyer, seller E3: Invalid Order Info, flavor G - general, M - wrong matcher, M2 unauthorized matcher, As - asset mismatch, AmB/AmS - amount mismatch (buyer,seller), PrB/PrS - price mismatch(buyer,seller), D - direction mismatch, U - Unit Converter Error, C - caller mismatch E4: Order expired, flavor B,S - buyer,seller E5: Contract not active, E6: Transfer error E7: Incorrect state prior to liquidation E8: Liquidator doesn't satisfy requirements E9: Data for liquidation handling is outdated E10: Incorrect state after liquidation E11: Amount overflow E12: Incorrect filled amount, flavor G,B,S: general(overflow), buyer order overflow, seller order overflow E14: Authorization error, sfs - seizeFromStake E15: Wrong passed params E16: Underlying protection mechanism error, flavor: R, I, O: Reentrancy, Initialization, Ownable */ }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./libs/MarginalFunctionality.sol"; // Base contract which contain state variable of the first version of Exchange // deployed on mainnet. Changes of the state variables should be introduced // not in that contract but down the inheritance chain, to allow safe upgrades // More info about safe upgrades here: // https://blog.openzeppelin.com/the-state-of-smart-contract-upgrades/#upgrade-patterns contract ExchangeStorage { //order -> filledAmount mapping(bytes32 => uint192) public filledAmounts; // Get user balance by address and asset address mapping(address => mapping(address => int192)) internal assetBalances; // List of assets with negative balance for each user mapping(address => MarginalFunctionality.Liability[]) public liabilities; // List of assets which can be used as collateral and risk coefficients for them address[] internal collateralAssets; mapping(address => uint8) public assetRisks; // Risk coefficient for locked ORN uint8 public stakeRisk; // Liquidation premium uint8 public liquidationPremium; // Delays after which price and position become outdated uint64 public priceOverdue; uint64 public positionOverdue; // Base orion tokens (can be locked on stake) IERC20 _orionToken; // Address of price oracle contract address _oracleAddress; // Address from which matching of orders is allowed address _allowedMatcher; //Adding gap_ due to previous OwnableUpgradeable implementation uint256[48] private gap_; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "./Exchange.sol"; import "./libs/LibAtomic.sol"; contract ExchangeWithAtomic is Exchange { uint256[2] private gap; address public WETH; mapping(bytes32 => LibAtomic.LockInfo) public atomicSwaps; mapping(bytes32 => bool) public secrets; event AtomicLocked(address sender, address asset, bytes32 secretHash); event AtomicRedeemed(address sender, address receiver, address asset, bytes secret); event AtomicClaimed(address receiver, address asset, bytes secret); event AtomicRefunded(address receiver, address asset, bytes32 secretHash); function setBasicParams( address orionToken, address priceOracleAddress, address allowedMatcher, address WETH_ ) public onlyOwner { _orionToken = IERC20(orionToken); _oracleAddress = priceOracleAddress; _allowedMatcher = allowedMatcher; WETH = WETH_; } function fillAndLockAtomic( LibAtomic.CrossChainOrder memory userOrder, LibValidator.Order memory brokerOrder, uint64 filledPrice, uint64 filledAmount, uint64 lockOrderExpiration ) public onlyMatcher { address lockAsset; uint64 lockAmount; if (userOrder.limitOrder.buySide == 1) { fillOrders(userOrder.limitOrder, brokerOrder, filledPrice, filledAmount); lockAsset = userOrder.limitOrder.baseAsset; lockAmount = filledAmount; } else { fillOrders(brokerOrder, userOrder.limitOrder, filledPrice, filledAmount); lockAsset = userOrder.limitOrder.quoteAsset; lockAmount = (filledAmount * filledPrice) / 10 ** 8; } LibAtomic.LockOrder memory lockOrder = LibAtomic.LockOrder({ sender: userOrder.limitOrder.matcherAddress, asset: lockAsset, amount: lockAmount, expiration: lockOrderExpiration, targetChainId: userOrder.chainId, secretHash: userOrder.secretHash }); _lockAtomic(userOrder.limitOrder.senderAddress, lockOrder); } function lockAtomicByMatcher(address account, LibAtomic.LockOrder memory lockOrder) external onlyMatcher { _lockAtomic(account, lockOrder); } function _lockAtomic(address account, LibAtomic.LockOrder memory lockOrder) internal nonReentrant { LibAtomic.doLockAtomic(account, lockOrder, atomicSwaps, assetBalances, liabilities); if (!checkPosition(account)) revert IncorrectPosition(); emit AtomicLocked(lockOrder.sender, lockOrder.asset, lockOrder.secretHash); } function lockAtomic(LibAtomic.LockOrder memory swap) public payable { _lockAtomic(msg.sender, swap); } function redeemAtomic(LibAtomic.RedeemOrder calldata order, bytes calldata secret) public { LibAtomic.doRedeemAtomic(order, secret, secrets, assetBalances, liabilities); if (!checkPosition(order.sender)) revert IncorrectPosition(); emit AtomicRedeemed(order.sender, order.receiver, order.asset, secret); } function redeem2Atomics( LibAtomic.RedeemOrder calldata order1, bytes calldata secret1, LibAtomic.RedeemOrder calldata order2, bytes calldata secret2 ) public { redeemAtomic(order1, secret1); redeemAtomic(order2, secret2); } function claimAtomic(address receiver, bytes calldata secret, bytes calldata matcherSignature) public { LibAtomic.LockInfo storage swap = LibAtomic.doClaimAtomic( receiver, secret, matcherSignature, _allowedMatcher, atomicSwaps, assetBalances, liabilities ); emit AtomicClaimed(receiver, swap.asset, secret); } function refundAtomic(bytes32 secretHash) public { LibAtomic.LockInfo storage swap = LibAtomic.doRefundAtomic(secretHash, atomicSwaps, assetBalances, liabilities); emit AtomicRefunded(swap.sender, swap.asset, secretHash); } /* Error Codes E1: Insufficient Balance, flavor A - Atomic, PA - Position Atomic E17: Incorrect atomic secret, flavor: U - used, NF - not found, R - redeemed, E/NE - expired/not expired, ETH */ }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Revert reason forwarder. library RevertReasonForwarder { /// @dev Forwards latest externall call revert. function reRevert() internal pure { // bubble up revert reason from latest external call assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; pragma abicoder v1; /// @title Interface for making arbitrary calls during swap interface IAggregationExecutor { /// @notice Make calls on `msgSender` with specified data function callBytes(address msgSender, bytes calldata data) external payable; // 0x2636f7f8 }
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; pragma abicoder v1; /// @title Interface for DAI-style permits interface IDaiLikePermit { function permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; pragma experimental ABIEncoderV2; interface IERC20Simple { function balanceOf(address account) external view returns (uint256); function decimals() external view returns (uint8); }
// SPDX-License-Identifier: GNU pragma solidity ^0.8.0; interface IWETH { function deposit() external payable; function balanceOf(address account) external view returns(uint256); function transfer(address to, uint value) external returns (bool); function withdraw(uint) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "./LibExchange.sol"; import "./LibValidator.sol"; library LibAtomic { using ECDSA for bytes32; struct LockOrder { address sender; uint64 expiration; address asset; uint64 amount; uint24 targetChainId; bytes32 secretHash; } struct LockInfo { address sender; uint64 expiration; bool used; address asset; uint64 amount; uint24 targetChainId; } struct ClaimOrder { address receiver; bytes32 secretHash; } struct RedeemOrder { address sender; address receiver; address claimReceiver; address asset; uint64 amount; uint64 expiration; bytes32 secretHash; bytes signature; } struct CrossChainOrder { LibValidator.Order limitOrder; uint24 chainId; bytes32 secretHash; } function doLockAtomic( address account, LockOrder memory swap, mapping(bytes32 => LockInfo) storage atomicSwaps, mapping(address => mapping(address => int192)) storage assetBalances, mapping(address => MarginalFunctionality.Liability[]) storage liabilities ) public { require(swap.expiration / 1000 >= block.timestamp, "E17E"); require(atomicSwaps[swap.secretHash].sender == address(0), "E17R"); int remaining = int(uint(swap.amount)); if (msg.value > 0) { require(swap.asset == address(0), "E17ETH"); uint eth_sent = uint(LibUnitConverter.baseUnitToDecimal(address(0), msg.value)); if (eth_sent < swap.amount) { remaining = int(uint(swap.amount)) - int(eth_sent); } else { swap.amount = uint64(eth_sent); remaining = 0; } } if (remaining > 0) { LibExchange._updateBalance(account, swap.asset, -1 * remaining, assetBalances, liabilities); require(assetBalances[account][swap.asset] >= 0, "E1A"); } atomicSwaps[swap.secretHash] = LockInfo( swap.sender, swap.expiration, false, swap.asset, swap.amount, swap.targetChainId ); } function doRedeemAtomic( LibAtomic.RedeemOrder calldata order, bytes calldata secret, mapping(bytes32 => bool) storage secrets, mapping(address => mapping(address => int192)) storage assetBalances, mapping(address => MarginalFunctionality.Liability[]) storage liabilities ) public { require(!secrets[order.secretHash], "E17R"); require(getEthSignedAtomicOrderHash(order).recover(order.signature) == order.sender, "E2"); require(order.expiration / 1000 >= block.timestamp, "E4A"); require(order.secretHash == keccak256(secret), "E17"); secrets[order.secretHash] = true; LibExchange._updateBalance(order.sender, order.asset, -1 * int(uint(order.amount)), assetBalances, liabilities); LibExchange._updateBalance(order.receiver, order.asset, int(uint(order.amount)), assetBalances, liabilities); } function doClaimAtomic( address receiver, bytes calldata secret, bytes calldata matcherSignature, address allowedMatcher, mapping(bytes32 => LockInfo) storage atomicSwaps, mapping(address => mapping(address => int192)) storage assetBalances, mapping(address => MarginalFunctionality.Liability[]) storage liabilities ) public returns (LockInfo storage swap) { bytes32 secretHash = keccak256(secret); bytes32 coHash = getEthSignedClaimOrderHash(ClaimOrder(receiver, secretHash)); require(coHash.recover(matcherSignature) == allowedMatcher, "E2"); swap = atomicSwaps[secretHash]; require(swap.sender != address(0), "E17NF"); // require(swap.expiration/1000 >= block.timestamp, "E17E"); require(!swap.used, "E17U"); swap.used = true; LibExchange._updateBalance(receiver, swap.asset, int(uint(swap.amount)), assetBalances, liabilities); } function doRefundAtomic( bytes32 secretHash, mapping(bytes32 => LockInfo) storage atomicSwaps, mapping(address => mapping(address => int192)) storage assetBalances, mapping(address => MarginalFunctionality.Liability[]) storage liabilities ) public returns (LockInfo storage swap) { swap = atomicSwaps[secretHash]; require(swap.sender != address(0x0), "E17NF"); require(swap.expiration / 1000 < block.timestamp, "E17NE"); require(!swap.used, "E17U"); swap.used = true; LibExchange._updateBalance(swap.sender, swap.asset, int(uint(swap.amount)), assetBalances, liabilities); } function getEthSignedAtomicOrderHash(RedeemOrder calldata _order) internal view returns (bytes32) { uint256 chId; assembly { chId := chainid() } return keccak256( abi.encodePacked( "atomicOrder", chId, _order.sender, _order.receiver, _order.claimReceiver, _order.asset, _order.amount, _order.expiration, _order.secretHash ) ).toEthSignedMessageHash(); } function getEthSignedClaimOrderHash(ClaimOrder memory _order) internal view returns (bytes32) { uint256 chId; assembly { chId := chainid() } return keccak256(abi.encodePacked("claimOrder", chId, _order.receiver, _order.secretHash)) .toEthSignedMessageHash(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./MarginalFunctionality.sol"; import "./LibUnitConverter.sol"; import "./LibValidator.sol"; import "./SafeTransferHelper.sol"; library LibExchange { using SafeERC20 for IERC20; // Flags for updateOrders // All flags are explicit uint8 public constant kSell = 0; uint8 public constant kBuy = 1; // if 0 - then sell uint8 public constant kCorrectMatcherFeeByOrderAmount = 2; event NewTrade( address indexed buyer, address indexed seller, address baseAsset, address quoteAsset, uint64 filledPrice, uint192 filledAmount, uint192 amountQuote ); event Trade( address indexed buyer, address indexed seller, address baseAsset, address quoteAsset, uint64 filledPrice, uint192 filledAmount, uint192 amountQuote, bytes32 tradeId ); event BalanceChange(address user, address asset, int192 delta); function _updateBalance( address user, address asset, int amount, mapping(address => mapping(address => int192)) storage assetBalances, mapping(address => MarginalFunctionality.Liability[]) storage liabilities ) internal returns (uint tradeType) { // 0 - in contract, 1 - from wallet int beforeBalance = int(assetBalances[user][asset]); int afterBalance = beforeBalance + amount; require((amount >= 0 && afterBalance >= beforeBalance) || (amount < 0 && afterBalance < beforeBalance), "E11"); if (amount > 0 && beforeBalance < 0) { MarginalFunctionality.updateLiability( user, asset, liabilities, uint112(uint256(amount)), int192(afterBalance) ); } else if (beforeBalance >= 0 && afterBalance < 0) { if (asset != address(0)) { afterBalance += int(_tryDeposit(asset, uint(-1 * afterBalance), user)); } // If we failed to deposit balance is still negative then we move user into liability if (afterBalance < 0) { setLiability(user, asset, int192(afterBalance), liabilities); } else { tradeType = beforeBalance > 0 ? 0 : 1; } } if (beforeBalance != afterBalance) { require(afterBalance >= type(int192).min && afterBalance <= type(int192).max, "E11"); int192 delta = int192(afterBalance) - assetBalances[user][asset]; assetBalances[user][asset] = int192(afterBalance); emit BalanceChange(user, asset, delta); } } /** * @dev method to add liability * @param user - user which created liability * @param asset - liability asset * @param balance - current negative balance */ function setLiability( address user, address asset, int192 balance, mapping(address => MarginalFunctionality.Liability[]) storage liabilities ) internal { liabilities[user].push( MarginalFunctionality.Liability({ asset: asset, timestamp: uint64(block.timestamp), outstandingAmount: uint192(-balance) }) ); } function _tryDeposit(address asset, uint amount, address user) internal returns (uint) { uint256 amountInBase = uint256(LibUnitConverter.decimalToBaseUnit(asset, amount)); // Query allowance before trying to transferFrom if ( IERC20(asset).balanceOf(user) >= amountInBase && IERC20(asset).allowance(user, address(this)) >= amountInBase ) { SafeERC20.safeTransferFrom(IERC20(asset), user, address(this), amountInBase); return amount; } else { return 0; } } function creditUserAssets( uint tradeType, address user, int amount, address asset, mapping(address => mapping(address => int192)) storage assetBalances, mapping(address => MarginalFunctionality.Liability[]) storage liabilities ) internal { int beforeBalance = int(assetBalances[user][asset]); int remainingAmount = amount + beforeBalance; require( (amount >= 0 && remainingAmount >= beforeBalance) || (amount < 0 && remainingAmount < beforeBalance), "E11" ); int sentAmount = 0; if (tradeType == 0 && asset == address(0) && user.balance < 1e16) { tradeType = 1; } if (tradeType == 1 && amount > 0 && remainingAmount > 0) { uint amountInBase = uint(LibUnitConverter.decimalToBaseUnit(asset, uint(amount))); uint contractBalance = asset == address(0) ? address(this).balance : IERC20(asset).balanceOf(address(this)); if (contractBalance >= amountInBase) { SafeTransferHelper.safeTransferTokenOrETH(asset, user, amountInBase); sentAmount = amount; } } int toUpdate = amount - sentAmount; if (toUpdate != 0) { _updateBalance(user, asset, toUpdate, assetBalances, liabilities); } } struct SwapBalanceChanges { int amountOut; address assetOut; int amountIn; address assetIn; } /** * @notice update user balances and send matcher fee * @param flags uint8, see constants for possible flags of order */ function updateOrderBalanceDebit( LibValidator.Order memory order, uint112 amountBase, uint112 amountQuote, uint8 flags, mapping(address => mapping(address => int192)) storage assetBalances, mapping(address => MarginalFunctionality.Liability[]) storage liabilities ) internal returns (uint tradeType, int actualIn) { bool isSeller = (flags & kBuy) == 0; { // Stack too deep bool isCorrectFee = ((flags & kCorrectMatcherFeeByOrderAmount) != 0); if (isCorrectFee) { // matcherFee: u64, filledAmount u128 => matcherFee*filledAmount fit u256 // result matcherFee fit u64 order.matcherFee = uint64((uint256(order.matcherFee) * amountBase) / order.amount); //rewrite in memory only } } if (amountBase > 0) { SwapBalanceChanges memory swap; (swap.amountOut, swap.amountIn) = isSeller ? (-1 * int(uint(amountBase)), int(uint(amountQuote))) : (-1 * int(uint(amountQuote)), int(uint(amountBase))); (swap.assetOut, swap.assetIn) = isSeller ? (order.baseAsset, order.quoteAsset) : (order.quoteAsset, order.baseAsset); uint feeTradeType = 1; if (order.matcherFeeAsset == swap.assetOut) { swap.amountOut -= int(uint(order.matcherFee)); } else if (order.matcherFeeAsset == swap.assetIn) { swap.amountIn -= int(uint(order.matcherFee)); } else { feeTradeType = _updateBalance( order.senderAddress, order.matcherFeeAsset, -1 * int256(uint256(order.matcherFee)), assetBalances, liabilities ); } tradeType = feeTradeType & _updateBalance(order.senderAddress, swap.assetOut, swap.amountOut, assetBalances, liabilities); actualIn = swap.amountIn; _updateBalance( order.matcherAddress, order.matcherFeeAsset, int256(uint256(order.matcherFee)), assetBalances, liabilities ); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/interfaces/IERC20.sol"; import "./LibValidator.sol"; import "./LibExchange.sol"; import "../interfaces/IAggregationExecutor.sol"; import "../utils/Errors.sol"; library LibGenericSwap { using SafeERC20 for IERC20; using SafeTransferHelper for IERC20; uint256 private constant _USE_EXCHANGE_BALANCE = 1 << 255; event OrionPoolSwap( address sender, address st, address rt, uint256 st_r, uint256 st_a, uint256 rt_r, uint256 rt_a, address f ); error EthDepositRejected(); error InsufficientReturnAmount(); error InsufficientBalance(); error ZeroMinReturnAmount(); function fillThroughPools( bytes32 orderHash, address senderAddress, IAggregationExecutor executor, LibValidator.SwapDescription memory desc, bytes calldata data ) external { uint112 filledAmount; uint112 quoteAmount; // stack too deep { (uint256 returnAmount, uint256 spentAmount, ) = swap(senderAddress, executor, desc, data); filledAmount = LibUnitConverter.baseUnitToDecimal(address(desc.srcToken), spentAmount); quoteAmount = LibUnitConverter.baseUnitToDecimal(address(desc.dstToken), returnAmount); } emit LibExchange.Trade( senderAddress, address(this), address(desc.srcToken), address(desc.dstToken), uint64((quoteAmount * 1e8) / filledAmount), filledAmount, quoteAmount, keccak256(abi.encode(orderHash, filledAmount)) ); } function swap( address sender, IAggregationExecutor executor, LibValidator.SwapDescription memory desc, bytes calldata data ) public returns (uint256 returnAmount, uint256 spentAmount, uint256 gasLeft) { (uint112 amount, uint112 minReturnAmount) = ( LibUnitConverter.decimalToBaseUnit(address(desc.srcToken), desc.amount), LibUnitConverter.decimalToBaseUnit(address(desc.dstToken), desc.minReturnAmount) ); if (minReturnAmount == 0) revert ZeroMinReturnAmount(); address payable dstReceiver = (desc.dstReceiver == address(0)) ? payable(sender) : desc.dstReceiver; returnAmount = desc.dstToken.uniBalanceOf(dstReceiver); _execute(sender, executor, data); returnAmount = desc.dstToken.uniBalanceOf(dstReceiver) - returnAmount; if (returnAmount < minReturnAmount) revert InsufficientReturnAmount(); gasLeft = gasleft(); spentAmount = amount; emit OrionPoolSwap( sender, address(desc.srcToken), address(desc.dstToken), spentAmount, spentAmount, returnAmount, returnAmount, address(0xA6E4Ce17474d790fb25E779F9317c55963D2cbdf) ); } function transferToInitialSource( address sender, LibValidator.SwapDescription memory desc, bytes calldata permit, mapping(address => mapping(address => int192)) storage assetBalances, mapping(address => MarginalFunctionality.Liability[]) storage liabilities ) external { bool srcETH = SafeTransferHelper.isETH(desc.srcToken); bool useExchangeBalance = desc.flags & _USE_EXCHANGE_BALANCE != 0; uint112 amount = LibUnitConverter.decimalToBaseUnit(address(desc.srcToken), desc.amount); if (!srcETH) { if (permit.length > 0) { desc.srcToken.safePermit(permit); } } if (useExchangeBalance) { if ((srcETH && (msg.value >= amount)) || (!srcETH && (msg.value != 0))) revert Errors.InvalidMsgValue(); int updateAmount = -int(desc.amount); if (srcETH) { uint112 valueInDecimal = LibUnitConverter.baseUnitToDecimal(address(0), msg.value); updateAmount += int(uint(valueInDecimal)); } if (updateAmount != 0) { LibExchange._updateBalance(sender, address(desc.srcToken), updateAmount, assetBalances, liabilities); } if (assetBalances[sender][address(desc.srcToken)] < 0) revert InsufficientBalance(); desc.srcToken.uniTransfer(desc.srcReceiver, amount); } else { if (msg.value != (srcETH ? amount : 0)) revert Errors.InvalidMsgValue(); if (!srcETH) { desc.srcToken.safeTransferFrom(sender, desc.srcReceiver, amount); } } } function _execute(address srcTokenOwner, IAggregationExecutor executor, bytes calldata data) private { bytes4 callBytesSelector = executor.callBytes.selector; assembly { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) mstore(ptr, callBytesSelector) mstore(add(ptr, 0x04), srcTokenOwner) calldatacopy(add(ptr, 0x24), data.offset, data.length) if iszero(call(gas(), executor, callvalue(), ptr, add(0x24, data.length), 0, 0)) { returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "../interfaces/IERC20Simple.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; library LibUnitConverter { using SafeMath for uint; /** @notice convert asset amount from8 decimals (10^8) to its base unit */ function decimalToBaseUnit(address assetAddress, uint amount) internal view returns (uint112 baseValue) { uint256 result; if (assetAddress == address(0)) { result = amount.mul(1 ether).div(10 ** 8); // 18 decimals } else { uint decimals = IERC20Simple(assetAddress).decimals(); result = amount.mul(10 ** decimals).div(10 ** 8); } require(result < uint112(type(int112).max), "E3U"); baseValue = uint112(result); } /** @notice convert asset amount from its base unit to 8 decimals (10^8) */ function baseUnitToDecimal(address assetAddress, uint amount) internal view returns (uint112 decimalValue) { uint256 result; if (assetAddress == address(0)) { result = amount.mul(10 ** 8).div(1 ether); } else { uint decimals = IERC20Simple(assetAddress).decimals(); result = amount.mul(10 ** 8).div(10 ** decimals); } require(result < uint112(type(int112).max), "E3U"); decimalValue = uint112(result); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/interfaces/IERC20.sol"; library LibValidator { using ECDSA for bytes32; string public constant DOMAIN_NAME = "Orion Exchange"; string public constant DOMAIN_VERSION = "1"; uint256 public constant CHAIN_ID = 1; bytes32 public constant DOMAIN_SALT = 0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a557; bytes32 public constant EIP712_DOMAIN_TYPEHASH = keccak256(abi.encodePacked("EIP712Domain(string name,string version,uint256 chainId,bytes32 salt)")); bytes32 public constant ORDER_TYPEHASH = keccak256( abi.encodePacked( "Order(address senderAddress,address matcherAddress,address baseAsset,address quoteAsset,address matcherFeeAsset,uint64 amount,uint64 price,uint64 matcherFee,uint64 nonce,uint64 expiration,uint8 buySide)" ) ); bytes32 public constant DOMAIN_SEPARATOR = keccak256( abi.encode( EIP712_DOMAIN_TYPEHASH, keccak256(bytes(DOMAIN_NAME)), keccak256(bytes(DOMAIN_VERSION)), CHAIN_ID, DOMAIN_SALT ) ); struct Order { address senderAddress; address matcherAddress; address baseAsset; address quoteAsset; address matcherFeeAsset; uint64 amount; uint64 price; uint64 matcherFee; uint64 nonce; uint64 expiration; uint8 buySide; // buy or sell bytes signature; } struct SwapDescription { IERC20 srcToken; IERC20 dstToken; address payable srcReceiver; address payable dstReceiver; uint256 amount; uint256 minReturnAmount; uint256 flags; } /** * @dev validate order signature */ function validateV3(Order memory order) public pure returns (bool, bytes32) { bytes32 orderHash = getTypeValueHash(order); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, orderHash)); return (digest.recover(order.signature) == order.senderAddress, orderHash); } /** * @return hash order */ function getTypeValueHash(Order memory _order) internal pure returns (bytes32) { return keccak256( abi.encode( ORDER_TYPEHASH, _order.senderAddress, _order.matcherAddress, _order.baseAsset, _order.quoteAsset, _order.matcherFeeAsset, _order.amount, _order.price, _order.matcherFee, _order.nonce, _order.expiration, _order.buySide ) ); } /** * @dev basic checks of matching orders against each other */ function checkOrdersInfo( Order memory buyOrder, Order memory sellOrder, address sender, uint256 filledAmount, uint256 filledPrice, uint256 currentTime, address allowedMatcher ) public pure returns (bytes32 buyOrderHash, bytes32 sellOrderHash) { bool isBuyOrderValid; bool isSellOrderValid; (isBuyOrderValid, buyOrderHash) = validateV3(buyOrder); (isSellOrderValid, sellOrderHash) = validateV3(sellOrder); require(isBuyOrderValid, "E2B"); require(isSellOrderValid, "E2S"); // Same matcher address require(buyOrder.matcherAddress == sender && sellOrder.matcherAddress == sender, "E3M"); if (allowedMatcher != address(0)) { require(buyOrder.matcherAddress == allowedMatcher, "E3M2"); } // Check matching assets require(buyOrder.baseAsset == sellOrder.baseAsset && buyOrder.quoteAsset == sellOrder.quoteAsset, "E3As"); // Check order amounts require(filledAmount <= buyOrder.amount, "E3AmB"); require(filledAmount <= sellOrder.amount, "E3AmS"); // Check Price values require(filledPrice <= buyOrder.price, "E3"); require(filledPrice >= sellOrder.price, "E3"); // Check Expiration Time. Convert to seconds first require(buyOrder.expiration / 1000 >= currentTime, "E4B"); require(sellOrder.expiration / 1000 >= currentTime, "E4S"); require(buyOrder.buySide == 1 && sellOrder.buySide == 0, "E3D"); } function getEthSignedOrderHash(Order memory _order) public pure returns (bytes32) { return keccak256( abi.encodePacked( "order", _order.senderAddress, _order.matcherAddress, _order.baseAsset, _order.quoteAsset, _order.matcherFeeAsset, _order.amount, _order.price, _order.matcherFee, _order.nonce, _order.expiration, _order.buySide ) ).toEthSignedMessageHash(); } function checkOrderSingleMatch( Order memory order, SwapDescription memory desc, uint256 filledAmount, uint256 currentTime ) internal pure returns (bytes32 orderHash) { bool isOrderValid; (isOrderValid, orderHash) = validateV3(order); require(isOrderValid, "E2B"); uint256 amountQuote = (uint256(filledAmount) * order.price) / 10 ** 8; uint256 amount_spend; uint256 amount_receive; if (order.buySide == 1) { require(order.quoteAsset == address(desc.srcToken) && order.baseAsset == address(desc.dstToken), "E3As"); (amount_spend, amount_receive) = (amountQuote, filledAmount); } else { require(order.baseAsset == address(desc.srcToken) && order.quoteAsset == address(desc.dstToken), "E3As"); (amount_spend, amount_receive) = (filledAmount, amountQuote); } require(order.senderAddress == desc.dstReceiver, "IncorrectReceiver"); require(amount_spend == desc.amount, "IncorrectAmount"); require(amount_receive >= desc.minReturnAmount, "IncorrectAmount"); require(filledAmount <= order.amount, "E3AmB"); require(order.expiration / 1000 >= currentTime, "E4B"); if (address(desc.dstToken) == order.matcherFeeAsset) { require(desc.minReturnAmount > order.matcherFee); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; pragma experimental ABIEncoderV2; import "../PriceOracleInterface.sol"; import "./LibExchange.sol"; library MarginalFunctionality { // We have the following approach: when liability is created we store // timestamp and size of liability. If the subsequent trade will deepen // this liability or won't fully cover it timestamp will not change. // However once outstandingAmount is covered we check whether balance on // that asset is positive or not. If not, liability still in the place but // time counter is dropped and timestamp set to `now`. struct Liability { address asset; uint64 timestamp; uint192 outstandingAmount; } enum PositionState { POSITIVE, NEGATIVE, // weighted position below 0 OVERDUE, // liability is not returned for too long NOPRICE, // some assets has no price or expired INCORRECT // some of the basic requirements are not met: too many liabilities, no locked stake, etc } struct Position { PositionState state; int256 weightedPosition; // sum of weighted collateral minus liabilities int256 totalPosition; // sum of unweighted (total) collateral minus liabilities int256 totalLiabilities; // total liabilities value } // Constants from Exchange contract used for calculations struct UsedConstants { address user; address _oracleAddress; address _orionTokenAddress; uint64 positionOverdue; uint64 priceOverdue; uint8 stakeRisk; uint8 liquidationPremium; } /** * @dev method to multiply numbers with uint8 based percent numbers */ function uint8Percent(int192 _a, uint8 _b) internal pure returns (int192 c) { int a = int256(_a); int b = int256(uint256(_b)); int d = 255; c = int192((a > 65536) ? (a / d) * b : (a * b) / d); } /** * @dev method to fetch asset prices in ORN tokens */ function getAssetPrice(address asset, address oracle) internal view returns (uint64 price, uint64 timestamp) { PriceOracleInterface.PriceDataOut memory assetPriceData = PriceOracleInterface(oracle).assetPrices(asset); (price, timestamp) = (assetPriceData.price, assetPriceData.timestamp); } /** * @dev method to calc weighted and absolute collateral value * @notice it only count for assets in collateralAssets list, all other assets will add 0 to position. * @return outdated whether any price is outdated * @return weightedPosition in ORN * @return totalPosition in ORN */ function calcAssets( address[] storage collateralAssets, mapping(address => mapping(address => int192)) storage assetBalances, mapping(address => uint8) storage assetRisks, address user, address orionTokenAddress, address oracleAddress, uint64 priceOverdue ) internal view returns (bool outdated, int192 weightedPosition, int192 totalPosition) { uint256 collateralAssetsLength = collateralAssets.length; for (uint256 i = 0; i < collateralAssetsLength; i++) { address asset = collateralAssets[i]; if (assetBalances[user][asset] < 0) continue; // will be calculated in calcLiabilities (uint64 price, uint64 timestamp) = (1e8, 0xfffffff000000000); if (asset != orionTokenAddress) { (price, timestamp) = getAssetPrice(asset, oracleAddress); } // balance: i192, price u64 => balance*price fits i256 // since generally balance <= N*maxInt112 (where N is number operations with it), // assetValue <= N*maxInt112*maxUInt64/1e8. // That is if N<= 2**17 *1e8 = 1.3e13 we can neglect overflows here uint8 specificRisk = assetRisks[asset]; int192 balance = assetBalances[user][asset]; int256 _assetValue = (int256(balance) * int256(uint256(price))) / 1e8; int192 assetValue = int192(_assetValue); // Overflows logic holds here as well, except that N is the number of // operations for all assets if (assetValue > 0) { weightedPosition += uint8Percent(assetValue, specificRisk); totalPosition += assetValue; outdated = outdated || ((timestamp + priceOverdue) < block.timestamp); } } return (outdated, weightedPosition, totalPosition); } /** * @dev method to calc liabilities * @return outdated whether any price is outdated * @return overdue whether any liability is overdue * @return weightedPosition weightedLiability == totalLiability in ORN * @return totalPosition totalLiability in ORN */ function calcLiabilities( mapping(address => Liability[]) storage liabilities, mapping(address => mapping(address => int192)) storage assetBalances, address user, address oracleAddress, uint64 positionOverdue, uint64 priceOverdue ) internal view returns (bool outdated, bool overdue, int192 weightedPosition, int192 totalPosition) { uint256 liabilitiesLength = liabilities[user].length; for (uint256 i = 0; i < liabilitiesLength; i++) { Liability storage liability = liabilities[user][i]; int192 balance = assetBalances[user][liability.asset]; (uint64 price, uint64 timestamp) = getAssetPrice(liability.asset, oracleAddress); // balance: i192, price u64 => balance*price fits i256 // since generally balance <= N*maxInt112 (where N is number operations with it), // assetValue <= N*maxInt112*maxUInt64/1e8. // That is if N<= 2**17 *1e8 = 1.3e13 we can neglect overflows here int192 liabilityValue = int192((int256(balance) * int256(uint256(price))) / 1e8); weightedPosition += liabilityValue; //already negative since balance is negative totalPosition += liabilityValue; overdue = overdue || ((liability.timestamp + positionOverdue) < block.timestamp); outdated = outdated || ((timestamp + priceOverdue) < block.timestamp); } return (outdated, overdue, weightedPosition, totalPosition); } /** * @dev method to calc Position * @return result position structure */ function calcPosition( address[] storage collateralAssets, mapping(address => Liability[]) storage liabilities, mapping(address => mapping(address => int192)) storage assetBalances, mapping(address => uint8) storage assetRisks, UsedConstants memory constants ) public view returns (Position memory result) { (bool outdatedPrice, int192 weightedPosition, int192 totalPosition) = calcAssets( collateralAssets, assetBalances, assetRisks, constants.user, constants._orionTokenAddress, constants._oracleAddress, constants.priceOverdue ); (bool _outdatedPrice, bool overdue, int192 _weightedPosition, int192 _totalPosition) = calcLiabilities( liabilities, assetBalances, constants.user, constants._oracleAddress, constants.positionOverdue, constants.priceOverdue ); weightedPosition += _weightedPosition; totalPosition += _totalPosition; outdatedPrice = outdatedPrice || _outdatedPrice; if (_totalPosition < 0) { result.totalLiabilities = _totalPosition; } if (weightedPosition < 0) { result.state = PositionState.NEGATIVE; } if (outdatedPrice) { result.state = PositionState.NOPRICE; } if (overdue) { result.state = PositionState.OVERDUE; } result.weightedPosition = weightedPosition; result.totalPosition = totalPosition; } /** * @dev method removes liability */ function removeLiability(address user, address asset, mapping(address => Liability[]) storage liabilities) public { uint256 length = liabilities[user].length; for (uint256 i = 0; i < length; i++) { if (liabilities[user][i].asset == asset) { if (length > 1) { liabilities[user][i] = liabilities[user][length - 1]; } liabilities[user].pop(); break; } } } /** * @dev method update liability * @notice implement logic for outstandingAmount (see Liability description) */ function updateLiability( address user, address asset, mapping(address => Liability[]) storage liabilities, uint112 depositAmount, int192 currentBalance ) internal { if (currentBalance >= 0) { removeLiability(user, asset, liabilities); } else { uint256 i; uint256 liabilitiesLength = liabilities[user].length; for (; i < liabilitiesLength - 1; i++) { if (liabilities[user][i].asset == asset) break; } Liability storage liability = liabilities[user][i]; if (depositAmount >= liability.outstandingAmount) { liability.outstandingAmount = uint192(-currentBalance); liability.timestamp = uint64(block.timestamp); } else { liability.outstandingAmount -= depositAmount; } } } /** * @dev partially liquidate, that is cover some asset liability to get ORN from misbehavior broker */ function partiallyLiquidate( address[] storage collateralAssets, mapping(address => Liability[]) storage liabilities, mapping(address => mapping(address => int192)) storage assetBalances, mapping(address => uint8) storage assetRisks, UsedConstants memory constants, address redeemedAsset, address collateralAsset, uint112 amount ) public { //Note: constants.user - is broker who will be liquidated Position memory initialPosition = calcPosition( collateralAssets, liabilities, assetBalances, assetRisks, constants ); require( initialPosition.state == PositionState.NEGATIVE || initialPosition.state == PositionState.OVERDUE, "E7" ); address liquidator = msg.sender; require(assetBalances[liquidator][redeemedAsset] >= int192(uint192(amount)), "E8"); require(assetBalances[constants.user][redeemedAsset] < 0, "E15"); assetBalances[liquidator][redeemedAsset] -= int192(uint192(amount)); assetBalances[constants.user][redeemedAsset] += int192(uint192(amount)); emit LibExchange.BalanceChange(liquidator, redeemedAsset, -int192(uint192(amount))); emit LibExchange.BalanceChange(constants.user, redeemedAsset, int192(uint192(amount))); if (assetBalances[constants.user][redeemedAsset] >= 0) removeLiability(constants.user, redeemedAsset, liabilities); (uint64 price, uint64 ts1) = getAssetPrice(redeemedAsset, constants._oracleAddress); require(ts1 + constants.priceOverdue > block.timestamp, "E9"); //Price is outdated if (collateralAsset != constants._orionTokenAddress) { // (uint64 collateralPrice, uint64 ts2) = getAssetPrice(collateralAsset, constants._oracleAddress); require(ts2 + constants.priceOverdue > block.timestamp, "E9"); //Price is outdated price = (price * 1e8) / collateralPrice; } reimburseLiquidator( amount, price, collateralAsset, liquidator, assetBalances, constants.liquidationPremium, constants.user ); Position memory finalPosition = calcPosition( collateralAssets, liabilities, assetBalances, assetRisks, constants ); require( uint(finalPosition.state) < 3 && //POSITIVE,NEGATIVE or OVERDUE (finalPosition.weightedPosition > initialPosition.weightedPosition), "E10" ); //Incorrect state position after liquidation if (finalPosition.state == PositionState.POSITIVE) require(finalPosition.weightedPosition < 10e8, "Can not liquidate to very positive state"); } /** * @dev reimburse liquidator with collateral: first from stake, than from broker balance */ function reimburseLiquidator( uint112 amount, uint64 price, address collateralAsset, address liquidator, mapping(address => mapping(address => int192)) storage assetBalances, uint8 liquidationPremium, address user ) internal { int192 collateralAmount = int192((int256(uint256(amount)) * int256(uint256(price))) / 1e8); collateralAmount += uint8Percent(collateralAmount, liquidationPremium); //Liquidation premium int192 onBalanceCollateral = assetBalances[user][collateralAsset]; require(onBalanceCollateral >= collateralAmount, "E10"); assetBalances[user][collateralAsset] -= collateralAmount; assetBalances[liquidator][collateralAsset] += collateralAmount; emit LibExchange.BalanceChange(user, collateralAsset, -collateralAmount); emit LibExchange.BalanceChange(liquidator, collateralAsset, collateralAmount); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../interfaces/IWETH.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../helpers/RevertReasonForwarder.sol"; import "../interfaces/IDaiLikePermit.sol"; library SafeTransferHelper { using SafeERC20 for IERC20; error InsufficientBalance(); error ForceApproveFailed(); error ApproveCalledOnETH(); error NotEnoughValue(); error FromIsNotSender(); error ToIsNotThis(); error ETHTransferFailed(); error SafePermitBadLength(); uint256 private constant _RAW_CALL_GAS_LIMIT = 5000; IERC20 private constant _ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); IERC20 private constant _ZERO_ADDRESS = IERC20(address(0)); /// @dev Returns true if `token` is ETH. function isETH(IERC20 token) internal pure returns (bool) { return (token == _ZERO_ADDRESS || token == _ETH_ADDRESS); } /// @dev Returns `account` ERC20 `token` balance. function uniBalanceOf(IERC20 token, address account) internal view returns (uint256) { if (isETH(token)) { return account.balance; } else { return token.balanceOf(account); } } /// @dev `token` transfer `to` `amount`. /// Note that this function does nothing in case of zero amount. /// @dev `token` transfer `to` `amount`. /// Note that this function does nothing in case of zero amount. function uniTransfer(IERC20 token, address payable to, uint256 amount) internal { if (amount > 0) { if (isETH(token)) { if (address(this).balance < amount) revert InsufficientBalance(); // solhint-disable-next-line avoid-low-level-calls (bool success, ) = to.call{value: amount, gas: _RAW_CALL_GAS_LIMIT}(""); if (!success) revert ETHTransferFailed(); } else { token.safeTransfer(to, amount); } } } /// @dev Reverts if `token` is ETH, otherwise performs ERC20 forceApprove. function uniApprove(IERC20 token, address to, uint256 amount) internal { if (isETH(token)) revert ApproveCalledOnETH(); forceApprove(token, to, amount); } /// @dev If `approve(from, to, amount)` fails, try to `approve(from, to, 0)` before retry. function forceApprove(IERC20 token, address spender, uint256 value) internal { if (!_makeCall(token, token.approve.selector, spender, value)) { if ( !_makeCall(token, token.approve.selector, spender, 0) || !_makeCall(token, token.approve.selector, spender, value) ) { revert ForceApproveFailed(); } } } function safeAutoTransferFrom(address weth, address token, address from, address to, uint value) internal { if (isETH(IERC20(token))) { require(from == address(this), "TransferFrom: this"); IWETH(weth).deposit{value: value}(); assert(IWETH(weth).transfer(to, value)); } else { if (from == address(this)) { SafeERC20.safeTransfer(IERC20(token), to, value); } else { SafeERC20.safeTransferFrom(IERC20(token), from, to, value); } } } function safeAutoTransferTo(address weth, address token, address to, uint value) internal { if (address(this) != to) { if (isETH(IERC20(token))) { IWETH(weth).withdraw(value); Address.sendValue(payable(to), value); } else { SafeERC20.safeTransfer(IERC20(token), to, value); } } } function safeTransferTokenOrETH(address token, address to, uint value) internal { if (value > 0) { if (isETH(IERC20(token))) { if (address(this).balance < value) revert InsufficientBalance(); // solhint-disable-next-line avoid-low-level-calls (bool success, ) = to.call{value: value, gas: _RAW_CALL_GAS_LIMIT}(""); if (!success) revert ETHTransferFailed(); } else { IERC20(token).safeTransfer(to, value); } } } function safePermit(IERC20 token, bytes calldata permit) internal { bool success; if (permit.length == 32 * 7) { // solhint-disable-next-line avoid-low-level-calls success = _makeCalldataCall(token, IERC20Permit.permit.selector, permit); } else if (permit.length == 32 * 8) { // solhint-disable-next-line avoid-low-level-calls success = _makeCalldataCall(token, IDaiLikePermit.permit.selector, permit); } else { revert SafePermitBadLength(); } if (!success) { RevertReasonForwarder.reRevert(); } } function _makeCall(IERC20 token, bytes4 selector, address to, uint256 amount) private returns (bool success) { assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let data := mload(0x40) mstore(data, selector) mstore(add(data, 0x04), to) mstore(add(data, 0x24), amount) success := call(gas(), token, 0, data, 0x44, 0x0, 0x20) if success { switch returndatasize() case 0 { success := gt(extcodesize(token), 0) } default { success := and(gt(returndatasize(), 31), eq(mload(0), 1)) } } } } function _makeCalldataCall(IERC20 token, bytes4 selector, bytes calldata args) private returns (bool done) { /// @solidity memory-safe-assembly assembly { // solhint-disable-line no-inline-assembly let len := add(4, args.length) let data := mload(0x40) mstore(data, selector) calldatacopy(add(data, 0x04), args.offset, args.length) let success := call(gas(), token, 0, data, len, 0x0, 0x20) done := and(success, or(iszero(returndatasize()), and(gt(returndatasize(), 31), eq(mload(0), 1)))) } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "./ExchangeStorage.sol"; import "./libs/LibExchange.sol"; abstract contract OrionVault is ExchangeStorage, ReentrancyGuard, OwnableUpgradeable { error NotEnoughBalance(); enum StakePhase { NOTSTAKED, LOCKED, RELEASING, READYTORELEASE, FROZEN } struct Stake { uint64 amount; // 100m ORN in circulation fits uint64 StakePhase phase; uint64 lastActionTimestamp; } uint64 constant releasingDuration = 3600 * 24; mapping(address => Stake) private stakingData; /** * @dev Returns locked or frozen stake balance only * @param user address */ function getLockedStakeBalance(address user) public view returns (uint256) { return stakingData[user].amount; } /** * @dev Request stake unlock for msg.sender * @dev If stake phase is LOCKED, that changes phase to RELEASING * @dev If stake phase is READYTORELEASE, that withdraws stake to balance * @dev Note, both unlock and withdraw is impossible if user has liabilities */ function requestReleaseStake() public { address user = _msgSender(); Stake storage stake = stakingData[user]; assetBalances[user][address(_orionToken)] += int192(uint192(stake.amount)); emit LibExchange.BalanceChange(user, address(_orionToken), int192(uint192(stake.amount))); stake.amount = 0; stake.phase = StakePhase.NOTSTAKED; } /** * @dev Lock some orions from exchange balance sheet * @param amount orions in 1e-8 units to stake */ function lockStake(uint64 amount) public { address user = _msgSender(); if (assetBalances[user][address(_orionToken)] < int192(uint192(amount))) revert NotEnoughBalance(); Stake storage stake = stakingData[user]; assetBalances[user][address(_orionToken)] -= int192(uint192(amount)); emit LibExchange.BalanceChange(user, address(_orionToken), -int192(uint192(amount))); stake.amount += amount; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; interface PriceOracleDataTypes { struct PriceDataOut { uint64 price; uint64 timestamp; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./PriceOracleDataTypes.sol"; interface PriceOracleInterface is PriceOracleDataTypes { function assetPrices(address) external view returns (PriceDataOut memory); function givePrices(address[] calldata assetAddresses) external view returns (PriceDataOut[] memory); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; pragma abicoder v1; library Errors { error ReturnAmountIsNotEnough(); error InvalidMsgValue(); error ERC20TransferFailed(); }
{ "optimizer": { "enabled": true, "runs": 1 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": { "contracts/libs/LibAtomic.sol": { "LibAtomic": "0x59723329a1e906629516b30ca9c30400b11a1ecd" }, "contracts/libs/LibGenericSwap.sol": { "LibGenericSwap": "0x4a7aa0fcf9b35d87b4125c90484497bb2e050e85" }, "contracts/libs/LibValidator.sol": { "LibValidator": "0xe8c2ac36f9e689f0b4b7c52d80b42fdfbd664567" }, "contracts/libs/MarginalFunctionality.sol": { "MarginalFunctionality": "0xdc91af7b038cc8760a0c53814f21be09caace0d7" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"AlreadyFilled","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"EthDepositRejected","type":"error"},{"inputs":[],"name":"Fallback","type":"error"},{"inputs":[],"name":"IncorrectPosition","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"NotCollateralAsset","type":"error"},{"inputs":[],"name":"NotEnoughBalance","type":"error"},{"inputs":[],"name":"OnlyMatcher","type":"error"},{"inputs":[],"name":"Overflow","type":"error"},{"inputs":[],"name":"ZeroReturnAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bytes","name":"secret","type":"bytes"}],"name":"AtomicClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bytes32","name":"secretHash","type":"bytes32"}],"name":"AtomicLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bytes","name":"secret","type":"bytes"}],"name":"AtomicRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bytes32","name":"secretHash","type":"bytes32"}],"name":"AtomicRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"isDeposit","type":"bool"},{"indexed":false,"internalType":"uint112","name":"amount","type":"uint112"},{"indexed":false,"internalType":"uint64","name":"timestamp","type":"uint64"}],"name":"NewAssetTransaction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"address","name":"baseAsset","type":"address"},{"indexed":false,"internalType":"address","name":"quoteAsset","type":"address"},{"indexed":false,"internalType":"uint64","name":"filledPrice","type":"uint64"},{"indexed":false,"internalType":"uint192","name":"filledAmount","type":"uint192"},{"indexed":false,"internalType":"uint192","name":"amountQuote","type":"uint192"},{"indexed":false,"internalType":"bytes32","name":"tradeId","type":"bytes32"}],"name":"Trade","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetRisks","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"atomicSwaps","outputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"bool","name":"used","type":"bool"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint24","name":"targetChainId","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"calcPosition","outputs":[{"components":[{"internalType":"enum MarginalFunctionality.PositionState","name":"state","type":"uint8"},{"internalType":"int256","name":"weightedPosition","type":"int256"},{"internalType":"int256","name":"totalPosition","type":"int256"},{"internalType":"int256","name":"totalLiabilities","type":"int256"}],"internalType":"struct MarginalFunctionality.Position","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"checkPosition","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"secret","type":"bytes"},{"internalType":"bytes","name":"matcherSignature","type":"bytes"}],"name":"claimAtomic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"uint112","name":"amount","type":"uint112"}],"name":"depositAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"uint112","name":"amount","type":"uint112"},{"internalType":"address","name":"account","type":"address"}],"name":"depositAssetTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"depositTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"address","name":"matcherAddress","type":"address"},{"internalType":"address","name":"baseAsset","type":"address"},{"internalType":"address","name":"quoteAsset","type":"address"},{"internalType":"address","name":"matcherFeeAsset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint64","name":"price","type":"uint64"},{"internalType":"uint64","name":"matcherFee","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint8","name":"buySide","type":"uint8"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibValidator.Order","name":"limitOrder","type":"tuple"},{"internalType":"uint24","name":"chainId","type":"uint24"},{"internalType":"bytes32","name":"secretHash","type":"bytes32"}],"internalType":"struct LibAtomic.CrossChainOrder","name":"userOrder","type":"tuple"},{"components":[{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"address","name":"matcherAddress","type":"address"},{"internalType":"address","name":"baseAsset","type":"address"},{"internalType":"address","name":"quoteAsset","type":"address"},{"internalType":"address","name":"matcherFeeAsset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint64","name":"price","type":"uint64"},{"internalType":"uint64","name":"matcherFee","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint8","name":"buySide","type":"uint8"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibValidator.Order","name":"brokerOrder","type":"tuple"},{"internalType":"uint64","name":"filledPrice","type":"uint64"},{"internalType":"uint64","name":"filledAmount","type":"uint64"},{"internalType":"uint64","name":"lockOrderExpiration","type":"uint64"}],"name":"fillAndLockAtomic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"address","name":"matcherAddress","type":"address"},{"internalType":"address","name":"baseAsset","type":"address"},{"internalType":"address","name":"quoteAsset","type":"address"},{"internalType":"address","name":"matcherFeeAsset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint64","name":"price","type":"uint64"},{"internalType":"uint64","name":"matcherFee","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint8","name":"buySide","type":"uint8"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibValidator.Order","name":"buyOrder","type":"tuple"},{"components":[{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"address","name":"matcherAddress","type":"address"},{"internalType":"address","name":"baseAsset","type":"address"},{"internalType":"address","name":"quoteAsset","type":"address"},{"internalType":"address","name":"matcherFeeAsset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint64","name":"price","type":"uint64"},{"internalType":"uint64","name":"matcherFee","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint8","name":"buySide","type":"uint8"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibValidator.Order","name":"sellOrder","type":"tuple"},{"internalType":"uint64","name":"filledPrice","type":"uint64"},{"internalType":"uint112","name":"filledAmount","type":"uint112"}],"name":"fillOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint112","name":"filledAmount","type":"uint112"},{"components":[{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"address","name":"matcherAddress","type":"address"},{"internalType":"address","name":"baseAsset","type":"address"},{"internalType":"address","name":"quoteAsset","type":"address"},{"internalType":"address","name":"matcherFeeAsset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint64","name":"price","type":"uint64"},{"internalType":"uint64","name":"matcherFee","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint8","name":"buySide","type":"uint8"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibValidator.Order","name":"order","type":"tuple"},{"internalType":"contract IAggregationExecutor","name":"executor","type":"address"},{"components":[{"internalType":"contract IERC20","name":"srcToken","type":"address"},{"internalType":"contract IERC20","name":"dstToken","type":"address"},{"internalType":"address payable","name":"srcReceiver","type":"address"},{"internalType":"address payable","name":"dstReceiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct LibValidator.SwapDescription","name":"desc","type":"tuple"},{"internalType":"bytes","name":"permit","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"fillThroughPools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"filledAmounts","outputs":[{"internalType":"uint192","name":"","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"getBalance","outputs":[{"internalType":"int192","name":"","type":"int192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assetsAddresses","type":"address[]"},{"internalType":"address","name":"user","type":"address"}],"name":"getBalances","outputs":[{"internalType":"int192[]","name":"balances","type":"int192[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCollateralAssets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"components":[{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"address","name":"matcherAddress","type":"address"},{"internalType":"address","name":"baseAsset","type":"address"},{"internalType":"address","name":"quoteAsset","type":"address"},{"internalType":"address","name":"matcherFeeAsset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint64","name":"price","type":"uint64"},{"internalType":"uint64","name":"matcherFee","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint8","name":"buySide","type":"uint8"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibValidator.Order","name":"order","type":"tuple"}],"name":"getFilledAmounts","outputs":[{"internalType":"int192","name":"totalFilled","type":"int192"},{"internalType":"int192","name":"totalFeesPaid","type":"int192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getLiabilities","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint192","name":"outstandingAmount","type":"uint192"}],"internalType":"struct MarginalFunctionality.Liability[]","name":"liabilitiesArray","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getLockedStakeBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"liabilities","outputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint192","name":"outstandingAmount","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationPremium","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint24","name":"targetChainId","type":"uint24"},{"internalType":"bytes32","name":"secretHash","type":"bytes32"}],"internalType":"struct LibAtomic.LockOrder","name":"swap","type":"tuple"}],"name":"lockAtomic","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint24","name":"targetChainId","type":"uint24"},{"internalType":"bytes32","name":"secretHash","type":"bytes32"}],"internalType":"struct LibAtomic.LockOrder","name":"lockOrder","type":"tuple"}],"name":"lockAtomicByMatcher","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"amount","type":"uint64"}],"name":"lockStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"broker","type":"address"},{"internalType":"address","name":"redeemedAsset","type":"address"},{"internalType":"address","name":"collateralAsset","type":"address"},{"internalType":"uint112","name":"amount","type":"uint112"}],"name":"partiallyLiquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"positionOverdue","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceOverdue","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"claimReceiver","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"bytes32","name":"secretHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibAtomic.RedeemOrder","name":"order1","type":"tuple"},{"internalType":"bytes","name":"secret1","type":"bytes"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"claimReceiver","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"bytes32","name":"secretHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibAtomic.RedeemOrder","name":"order2","type":"tuple"},{"internalType":"bytes","name":"secret2","type":"bytes"}],"name":"redeem2Atomics","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"claimReceiver","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"bytes32","name":"secretHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibAtomic.RedeemOrder","name":"order","type":"tuple"},{"internalType":"bytes","name":"secret","type":"bytes"}],"name":"redeemAtomic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"secretHash","type":"bytes32"}],"name":"refundAtomic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestReleaseStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"secrets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"orionToken","type":"address"},{"internalType":"address","name":"priceOracleAddress","type":"address"},{"internalType":"address","name":"allowedMatcher","type":"address"},{"internalType":"address","name":"WETH_","type":"address"}],"name":"setBasicParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeRisk","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IAggregationExecutor","name":"executor","type":"address"},{"components":[{"internalType":"contract IERC20","name":"srcToken","type":"address"},{"internalType":"contract IERC20","name":"dstToken","type":"address"},{"internalType":"address payable","name":"srcReceiver","type":"address"},{"internalType":"address payable","name":"dstReceiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct LibValidator.SwapDescription","name":"desc","type":"tuple"},{"internalType":"bytes","name":"permit","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"spentAmount","type":"uint256"},{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint8[]","name":"risks","type":"uint8[]"}],"name":"updateAssetRisks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_collateralAssets","type":"address[]"},{"internalType":"uint8","name":"_stakeRisk","type":"uint8"},{"internalType":"uint8","name":"_liquidationPremium","type":"uint8"},{"internalType":"uint64","name":"_priceOverdue","type":"uint64"},{"internalType":"uint64","name":"_positionOverdue","type":"uint64"}],"name":"updateMarginalSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"address","name":"matcherAddress","type":"address"},{"internalType":"address","name":"baseAsset","type":"address"},{"internalType":"address","name":"quoteAsset","type":"address"},{"internalType":"address","name":"matcherFeeAsset","type":"address"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint64","name":"price","type":"uint64"},{"internalType":"uint64","name":"matcherFee","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint8","name":"buySide","type":"uint8"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibValidator.Order","name":"order","type":"tuple"}],"name":"validateOrder","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"uint112","name":"amount","type":"uint112"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"uint112","name":"amount","type":"uint112"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b506001603955615fb380620000266000396000f3fe6080604052600436106102065760003560e01c806311fbc3091461025357806312aa3caf1461029657806315ba55e5146102c457806318044e80146102e4578063253d73a81461030457806328d0a326146103245780632b3a54411461034b57806340f1a34d1461036b5780634e91d2c6146103b9578063548dd437146103d957806355664d37146103ee5780636241d7681461043b57806362a3f4dd1461047d5780636628b4641461049d5780636c3175bb146104bd578063715018a6146104d05780638129fc1c146104e55780638293e9af146104ed5780638795e1bb1461050d57806388a0ec621461052d5780638da5cb5b1461054d578063963ad20c1461056f578063a02fbb781461058f578063a0a90856146105af578063a1ff9bee1461066f578063a5ffc19a14610691578063a9d5ec76146106cb578063ad5c4648146106eb578063b0d3b87e1461070b578063b760faf91461072b578063c18c9d931461073e578063d0e30db01461076e578063d1c0702814610776578063d4fac45d146107a3578063dcffd7cb146107d6578063e0c3ebcf146107f0578063e326dbbf14610810578063e4fd7d0114610830578063e658defb14610850578063e6b8b82514610870578063ef74e5941461088f578063f2fde38b146108bf578063f721599e146108df578063f7522af61461090c578063ff782d9b146109625761022d565b3661022d5732330361022b57604051631b10b0f960e01b815260040160405180910390fd5b005b34801561023957600080fd5b506040516314ad190f60e21b815260040160405180910390fd5b34801561025f57600080fd5b50600554610279906201000090046001600160401b031681565b6040516001600160401b0390911681526020015b60405180910390f35b6102a96102a4366004614474565b61098f565b6040805193845260208401929092529082015260600161028d565b3480156102d057600080fd5b5061022b6102df3660046146c5565b610ad1565b3480156102f057600080fd5b5061022b6102ff3660046147be565b610bde565b34801561031057600080fd5b5061022b61031f36600461483d565b610cef565b34801561033057600080fd5b5060055461027990600160501b90046001600160401b031681565b34801561035757600080fd5b5061022b610366366004614919565b610ee4565b34801561037757600080fd5b506103a16103863660046149b2565b6000602081905290815260409020546001600160c01b031681565b6040516001600160c01b03909116815260200161028d565b3480156103c557600080fd5b5061022b6103d43660046149cb565b610f02565b3480156103e557600080fd5b5061022b611056565b3480156103fa57600080fd5b5061042d6104093660046149e6565b6001600160a01b03166000908152609f60205260409020546001600160401b031690565b60405190815260200161028d565b34801561044757600080fd5b5061046b6104563660046149e6565b60046020526000908152604090205460ff1681565b60405160ff909116815260200161028d565b34801561048957600080fd5b5061022b610498366004614a03565b61111c565b3480156104a957600080fd5b5061022b6104b83660046149b2565b61120d565b61022b6104cb366004614b23565b6112ed565b3480156104dc57600080fd5b5061022b6112fa565b61022b61130e565b3480156104f957600080fd5b5061022b610508366004614b3f565b61142a565b34801561051957600080fd5b5061022b610528366004614b6b565b611439565b34801561053957600080fd5b5061022b610548366004614b3f565b611591565b34801561055957600080fd5b5061056261159c565b60405161028d9190614bc1565b34801561057b57600080fd5b5061022b61058a366004614b6b565b6115ab565b34801561059b57600080fd5b5061022b6105aa366004614c19565b6117db565b3480156105bb57600080fd5b506106216105ca3660046149b2565b60a360205260009081526040902080546001909101546001600160a01b03808316926001600160401b03600160a01b80830482169460ff600160e01b9485900416948116939181049092169162ffffff9190041686565b604080516001600160a01b0397881681526001600160401b0396871660208201529415159085015294909116606083015291909116608082015262ffffff90911660a082015260c00161028d565b34801561067b57600080fd5b50610684611884565b60405161028d9190614c84565b34801561069d57600080fd5b506106b16106ac366004614cd1565b6118e6565b60408051601793840b81529190920b60208201520161028d565b3480156106d757600080fd5b5061022b6106e6366004614d17565b611937565b3480156106f757600080fd5b5060a254610562906001600160a01b031681565b34801561071757600080fd5b5061022b610726366004614d9b565b611c2f565b61022b6107393660046149e6565b611d3a565b34801561074a57600080fd5b5061075e6107593660046149e6565b611d58565b604051901515815260200161028d565b61022b611da3565b34801561078257600080fd5b50610796610791366004614ddc565b611dac565b60405161028d9190614e9f565b3480156107af57600080fd5b506107c36107be366004614eda565b611ea4565b60405160179190910b815260200161028d565b3480156107e257600080fd5b5060055461046b9060ff1681565b3480156107fc57600080fd5b5061022b61080b366004614f13565b611ed4565b34801561081c57600080fd5b5061022b61082b366004614f9a565b611f4a565b34801561083c57600080fd5b5061075e61084b366004614ff6565b611fa2565b34801561085c57600080fd5b5061022b61086b36600461502a565b61201c565b34801561087c57600080fd5b5060055461046b90610100900460ff1681565b34801561089b57600080fd5b5061075e6108aa3660046149b2565b60a46020526000908152604090205460ff1681565b3480156108cb57600080fd5b5061022b6108da3660046149e6565b612051565b3480156108eb57600080fd5b506108ff6108fa3660046149e6565b6120c7565b60405161028d9190615057565b34801561091857600080fd5b5061092c6109273660046150cb565b612173565b604080516001600160a01b0390941684526001600160401b0390921660208401526001600160c01b03169082015260600161028d565b34801561096e57600080fd5b5061098261097d3660046149e6565b6121d2565b60405161028d919061510d565b600080600061099c612296565b8760a001516000036109c1576040516328ebf24760e01b815260040160405180910390fd5b604051632c1affb960e01b8152734a7aa0fcf9b35d87b4125c90484497bb2e050e8590632c1affb990610a049033908c908c908c906001906002906004016151d7565b60006040518083038186803b158015610a1c57600080fd5b505af4158015610a30573d6000803e3d6000fd5b5050604051632da073a160e01b8152734a7aa0fcf9b35d87b4125c90484497bb2e050e859250632da073a19150610a739033908d908d908b908b90600401615221565b606060405180830381865af4158015610a90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab49190615267565b91945092509050610ac56001603955565b96509650969350505050565b6008546001600160a01b03163314610afc576040516387ece76560e01b815260040160405180910390fd5b6000808660000151610140015160ff16600103610b38578651610b2a9087876001600160401b038816611937565b505084516040015182610b75565b610b5186886000015187876001600160401b0316611937565b86516060015191506305f5e100610b6886866152ab565b610b7291906152f0565b90505b6040805160c08101825288516020908101516001600160a01b0390811683526001600160401b0380881683850152908616838501528416606083015289015162ffffff1660808201529088015160a0820152875151610bd490826122ef565b5050505050505050565b604051634a3e552760e11b81527359723329a1e906629516b30ca9c30400b11a1ecd9063947caa4e90610c229086908690869060a49060019060029060040161535b565b60006040518083038186803b158015610c3a57600080fd5b505af4158015610c4e573d6000803e3d6000fd5b50610c64925061075991505060208501856149e6565b610c815760405163188da0b360e21b815260040160405180910390fd5b7f62d93a8b1423235bfd6a4737b2e2069ee7c9ef53c8dab794a345f4d988d3f7e5610caf60208501856149e6565b610cbf60408601602087016149e6565b610ccf60808701606088016149e6565b8585604051610ce2959493929190615467565b60405180910390a1505050565b6008546001600160a01b03163314610d1a576040516387ece76560e01b815260040160405180910390fd5b610d22612296565b6000610d41610d308961549c565b878b6001600160701b031642612441565b9050610d5360a0890160808a016149e6565b6001600160a01b031686602001516001600160a01b031614610d8557610d80610d7b8961549c565b612713565b610db4565b610d96610100890160e08a016149cb565b6001600160401b03168660a001818151610db091906154a8565b9052505b734a7aa0fcf9b35d87b4125c90484497bb2e050e85632c1affb9610ddb60208b018b6149e6565b888888600160026040518763ffffffff1660e01b8152600401610e03969594939291906151d7565b60006040518083038186803b158015610e1b57600080fd5b505af4158015610e2f573d6000803e3d6000fd5b50734a7aa0fcf9b35d87b4125c90484497bb2e050e85925063d5542b6b9150839050610e5e60208c018c6149e6565b8a8a88886040518763ffffffff1660e01b8152600401610e83969594939291906154bf565b60006040518083038186803b158015610e9b57600080fd5b505af4158015610eaf573d6000803e3d6000fd5b50505050610ed9818960a0016020810190610eca91906149cb565b6001600160401b03168b6127b6565b50610bd46001603955565b610eef868686610bde565b610efa838383610bde565b505050505050565b3360008181526001602090815260408083206006546001600160a01b031684529091529020546001600160401b038316601790810b91900b1215610f595760405163569d45cf60e11b815260040160405180910390fd5b6001600160a01b038082166000908152609f6020908152604080832060018352818420600654909516845293909152812080546001600160401b0386169290610fa690849060170b61550c565b82546001600160c01b039182166101009390930a928302919092021990911617905550600654600080516020615f3e8339815191529083906001600160a01b0316610ff96001600160401b03871661555c565b6040516110089392919061557f565b60405180910390a180548390829060009061102d9084906001600160401b03166155a6565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550505050565b336000818152609f602090815260408083208054600184528285206006546001600160a01b03168652909352908320805491936001600160401b039093169290916110a590849060170b6155d1565b82546001600160c01b039182166101009390930a9283029190920219909116179055506006548154604051600080516020615f3e833981519152926111039286926001600160a01b03909216916001600160401b039091169061557f565b60405180910390a180546001600160481b031916905550565b6008546040516321963ec160e01b81526000917359723329a1e906629516b30ca9c30400b11a1ecd916321963ec191611174918a918a918a918a918a916001600160a01b03169060a390600190600290600401615622565b602060405180830381865af4158015611191573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b59190615682565b60018101546040519192507fe4efc926785e8287f79fae88209e8625600f4493b87d12e6eff70d9eba5bc755916111fd9189916001600160a01b03909116908990899061569b565b60405180910390a1505050505050565b604051632f7f859560e01b81526004810182905260a3602482015260016044820152600260648201526000907359723329a1e906629516b30ca9c30400b11a1ecd90632f7f859590608401602060405180830381865af4158015611275573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112999190615682565b805460018201546040519293507faa0d989110241a1a8280e797bfec099d9846f91bf9b168fc911a329ad7fa0228926112e1926001600160a01b0390811692169086906156d2565b60405180910390a15050565b6112f733826122ef565b50565b611302612847565b61130c60006128a6565b565b603a54610100900460ff161580801561132e5750603a54600160ff909116105b8061134f575061133d306128f8565b15801561134f5750603a5460ff166001145b6113b75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b603a805460ff1916600117905580156113da57603a805461ff0019166101001790555b6113e2612907565b80156112f757603a805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b6114358282336115ab565b5050565b611441612296565b6040516370a0823160e01b81526000906001600160a01b038516906370a0823190611470903090600401614bc1565b602060405180830381865afa15801561148d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b19190615682565b90506114d16001600160a01b03851633306001600160701b038716612936565b6040516370a0823160e01b815281906001600160a01b038616906370a08231906114ff903090600401614bc1565b602060405180830381865afa15801561151c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115409190615682565b61154a91906154a8565b9050826001600160701b03168110156115765760405163569d45cf60e11b815260040160405180910390fd5b61158184828461298e565b5061158c6001603955565b505050565b611435828233611439565b606d546001600160a01b031690565b6115b3612296565b60006115c884846001600160701b0316612b09565b3360009081526001602090815260408083206001600160a01b0389168452909152812080549293506001600160701b0384169290919061160c90849060170b61550c565b92506101000a8154816001600160c01b03021916908360170b6001600160c01b03160217905550600080516020615f3e8339815191528285836001600160701b03166116579061555c565b6040516116669392919061557f565b60405180910390a13360009081526001602090815260408083206001600160a01b038816845290915281205460170b12156116b45760405163569d45cf60e11b815260040160405180910390fd5b6116bd82611d58565b6116da5760405163188da0b360e21b815260040160405180910390fd5b6001600160a01b03841661176b576000826001600160a01b0316846001600160701b031660405160006040518083038185875af1925050503d806000811461173e576040519150601f19603f3d011682016040523d82523d6000602084013e611743565b606091505b50509050806117655760405163569d45cf60e11b815260040160405180910390fd5b50611788565b6117886001600160a01b038516836001600160701b038616612c06565b836001600160a01b0316826001600160a01b0316336001600160a01b0316600080516020615f5e833981519152600085426040516117c8939291906156f6565b60405180910390a45061158c6001603955565b6117e3612847565b60005b8381101561187d5782828281811061180057611800615720565b90506020020160208101906118159190615736565b6004600087878581811061182b5761182b615720565b905060200201602081019061184091906149e6565b6001600160a01b031681526020810191909152604001600020805460ff191660ff929092169190911790558061187581615753565b9150506117e6565b5050505050565b606060038054806020026020016040519081016040528092919081815260200182805480156118dc57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116118be575b5050505050905090565b60008281526020819052604081205460a083015160e08401516001600160c01b0390921692916001600160401b03918216916119249185911661576c565b61192e919061578b565b90509250929050565b61193f612296565b60006305f5e1006119626001600160401b0385166001600160701b03851661576c565b61196c919061578b565b90506001600160701b03811061199557604051631a93c68960e11b815260040160405180910390fd5b60085460405163c956a3b760e01b81528291600091829173e8c2ac36f9e689f0b4b7c52d80b42fdfbd6645679163c956a3b7916119ec918c918c9133918c918e9142916001600160a01b03909116906004016158dd565b6040805180830381865af4158015611a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2c9190615950565b91509150611a48828960a001516001600160401b0316876127b6565b611a60818860a001516001600160401b0316876127b6565b611a8b6040518060800160405280600081526020016000815260200160008152602001600081525090565b611a9c898786600360016002612c36565b60408301528152611ab38887866002600181612c36565b6060830152602082015280518951604080840151908c0151611adb9392919060016002612e4a565b611afb8160200151896000015183606001518b6060015160016002612e4a565b8851611b0690611d58565b611b235760405163188da0b360e21b815260040160405180910390fd5b8751611b2e90611d58565b611b4b5760405163188da0b360e21b815260040160405180910390fd5b87600001516001600160a01b031689600001516001600160a01b03167f22aceb00bb2ded7eb0facc722fa061971f5950b739ecb216300e019b74ccd4a08b604001518c606001518b8b8a8a8a604051602001611bb1929190918252602082015260400190565b60408051601f1981840301815282825280516020918201206001600160a01b03988916845296909716968201969096526001600160401b0393909316838601526001600160701b03918216606084015216608082015260a081019190915290519081900360c00190a35050505050611c296001603955565b50505050565b6000805b600354811015611c8d57836001600160a01b031660038281548110611c5a57611c5a615720565b6000918252602090912001546001600160a01b031603611c7d5760019150611c8d565b611c8681615753565b9050611c33565b5080611cac5760405163a87fa00b60e01b815260040160405180910390fd5b6000611cb786613005565b6040516309f70f0560e31b815290915073dc91af7b038cc8760a0c53814f21be09caace0d790634fb8782890611d029060039060029060019060049088908d908d908d9085016159da565b60006040518083038186803b158015611d1a57600080fd5b505af4158015611d2e573d6000803e3d6000fd5b50505050505050505050565b611d42612296565b611d4e6000348361298e565b6112f76001603955565b6001600160a01b0381166000908152600260205260408120548103611d7f57506001919050565b6000611d8a836121d2565b516004811115611d9c57611d9c6150f7565b1492915050565b61130c33611d3a565b606082516001600160401b03811115611dc757611dc76142fb565b604051908082528060200260200182016040528015611df0578160200160208202803683370190505b50905060005b8351811015611e9d576001600160a01b03831660009081526001602052604081208551909190869084908110611e2e57611e2e615720565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900460170b828281518110611e7657611e76615720565b602002602001019060170b908160170b815250508080611e9590615753565b915050611df6565b5092915050565b6001600160a01b0380821660009081526001602090815260408083209386168352929052205460170b5b92915050565b611edc612847565b611ee860038787614251565b506005805460ff95861661ffff199091161761010094909516939093029390931762010000600160901b031916620100006001600160401b0392831602600160501b600160901b03191617600160501b93909116929092029190911790555050565b611f52612847565b600680546001600160a01b039586166001600160a01b0319918216179091556007805494861694821694909417909355600880549285169284169290921790915560a28054919093169116179055565b60405163e7e652ed60e01b815260009073e8c2ac36f9e689f0b4b7c52d80b42fdfbd6645679063e7e652ed90611fdc908590600401615a3c565b6040805180830381865af4158015611ff8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e9d9190615a5f565b6008546001600160a01b03163314612047576040516387ece76560e01b815260040160405180910390fd5b61143582826122ef565b612059612847565b6001600160a01b0381166120be5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016113ae565b6112f7816128a6565b6001600160a01b0381166000908152600260209081526040808320805482518185028101850190935280835260609492939192909184015b82821015612168576000848152602090819020604080516060810182526002860290920180546001600160a01b0381168452600160a01b90046001600160401b0316838501526001908101546001600160c01b03169183019190915290835290920191016120ff565b505050509050919050565b6002602052816000526040600020818154811061218f57600080fd5b6000918252602090912060029091020180546001909101546001600160a01b0382169350600160a01b9091046001600160401b031691506001600160c01b031683565b6121fe604080516080810190915280600081526020016000815260200160008152602001600081525090565b600061220983613005565b60405163f127baa160e01b815290915073dc91af7b038cc8760a0c53814f21be09caace0d79063f127baa19061224e9060039060029060019060049088908201615a8b565b608060405180830381865af415801561226b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228f9190615ab6565b9392505050565b6002603954036122e85760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016113ae565b6002603955565b6122f7612296565b6040805163c568f68560e01b81526001600160a01b03808516600483015283518116602483015260208401516001600160401b0390811660448401529284015116606482015260608301519091166084820152608082015162ffffff1660a482015260a082015160c482015260a360e4820152600161010482015260026101248201527359723329a1e906629516b30ca9c30400b11a1ecd9063c568f685906101440160006040518083038186803b1580156123b257600080fd5b505af41580156123c6573d6000803e3d6000fd5b505050506123d382611d58565b6123f05760405163188da0b360e21b815260040160405180910390fd5b7f8156ea5248573c664d8d0995ccb941c2cd87e2e6fa12d8a56594295bae8d14bb816000015182604001518360a0015160405161242f939291906156d2565b60405180910390a16114356001603955565b60008061244d866130a8565b92509050806124845760405162461bcd60e51b815260206004820152600360248201526222992160e91b60448201526064016113ae565b60006305f5e1008760c001516001600160401b0316866124a4919061576c565b6124ae919061578b565b905060008088610140015160ff1660010361252b5787600001516001600160a01b031689606001516001600160a01b0316148015612505575087602001516001600160a01b031689604001516001600160a01b0316145b6125215760405162461bcd60e51b81526004016113ae90615b28565b508190508561258f565b87600001516001600160a01b031689604001516001600160a01b031614801561256d575087602001516001600160a01b031689606001516001600160a01b0316145b6125895760405162461bcd60e51b81526004016113ae90615b28565b50859050815b87606001516001600160a01b031689600001516001600160a01b0316146125ec5760405162461bcd60e51b815260206004820152601160248201527024b731b7b93932b1ba2932b1b2b4bb32b960791b60448201526064016113ae565b8760800151821461260f5760405162461bcd60e51b81526004016113ae90615b46565b8760a001518110156126335760405162461bcd60e51b81526004016113ae90615b46565b8860a001516001600160401b03168711156126785760405162461bcd60e51b81526020600482015260056024820152642299a0b6a160d91b60448201526064016113ae565b856103e88a610120015161268c91906152f0565b6001600160401b031610156126c95760405162461bcd60e51b8152602060048201526003602482015262229a2160e91b60448201526064016113ae565b88608001516001600160a01b031688602001516001600160a01b031603612707578860e001516001600160401b03168860a001511161270757600080fd5b50505050949350505050565b612740816000015182608001518360e001516001600160401b031661273790615b6f565b60016002613272565b5080516001600160a01b039081166000908152600160209081526040808320608086015190941683529290529081205460170b121561279257604051631e9acf1760e31b815260040160405180910390fd5b611435816020015182608001518360e001516001600160401b031660016002613272565b6000838152602081905260409020546001600160c01b03166127e16001600160701b03831682615b8b565b9050826001600160c01b0316816001600160c01b03161115612816576040516341a26a6360e01b815260040160405180910390fd5b60009384526020849052604090932080546001600160c01b0319166001600160c01b03909416939093179092555050565b3361285061159c565b6001600160a01b03161461130c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016113ae565b606d80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b03163b151590565b603a54610100900460ff1661292e5760405162461bcd60e51b81526004016113ae90615bad565b61130c613471565b611c29846323b872dd60e01b858585604051602401612957939291906156d2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526134a1565b6001600160a01b03808216600090815260016020908152604080832093871683529290529081205460170b8113906129cf856001600160701b038616612b09565b6001600160a01b038085166000908152600160209081526040808320938a16835292905290812080549293506001600160701b03841692909190612a1790849060170b6155d1565b92506101000a8154816001600160c01b03021916908360170b6001600160c01b03160217905550600080516020615f3e8339815191528386836001600160701b0316604051612a689392919061557f565b60405180910390a16001600160701b03841615612ac857846001600160a01b0316836001600160a01b0316336001600160a01b0316600080516020615f5e83398151915260018542604051612abf939291906156f6565b60405180910390a45b811561187d576001600160a01b0380841660009081526001602090815260408083209389168352929052205461187d9084908790600290859060170b613576565b6000806001600160a01b038416612b4157612b3a670de0b6b3a7640000612b34856305f5e100613720565b9061372c565b9050612bca565b6000846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba59190615bf8565b60ff169050612bc6612bb882600a615cf9565b612b34866305f5e100613720565b9150505b60016001606f1b03811061228f5760405162461bcd60e51b815260206004820152600360248201526245335560e81b60448201526064016113ae565b6040516001600160a01b03831660248201526044810182905261158c90849063a9059cbb60e01b90606401612957565b60008060018516156002861615801590612c93578960a001516001600160401b0316896001600160701b03168b60e001516001600160401b0316612c7a919061576c565b612c84919061578b565b6001600160401b031660e08b01525b506001600160701b03881615612e3e5760408051608081018252600080825260208201819052918101829052606081019190915281612cf057612ce16001600160701b038916600019615d05565b896001600160701b0316612d10565b612d056001600160701b038a16600019615d05565b886001600160701b03165b6040830152815281612d2b5789606001518a60400151612d36565b89604001518a606001515b6001600160a01b0390811660608401529081166020830181905260808c01516001921603612d85578a60e001516001600160401b031682600001818151612d7d9190615d8a565b905250612df7565b81606001516001600160a01b03168b608001516001600160a01b031603612dc5578a60e001516001600160401b031682604001818151612d7d9190615d8a565b612df48b600001518c608001518d60e001516001600160401b0316600019612ded9190615d05565b8a8a613272565b90505b8a5160208301518351612e0d9291908a8a613272565b8116945081604001519350612e3a8b602001518c608001518d60e001516001600160401b03168a8a613272565b5050505b50965096945050505050565b6001600160a01b0380861660009081526020848152604080832093871683529290529081205460170b90612e7e8287615dc9565b905060008612158015612e915750818112155b80612ea65750600086128015612ea657508181125b612ec25760405162461bcd60e51b81526004016113ae90615e0a565b600088158015612ed957506001600160a01b038616155b8015612ef55750662386f26fc10000886001600160a01b031631105b15612eff57600198505b886001148015612f0f5750600087135b8015612f1b5750600082135b15612fd7576000612f2c8789613738565b6001600160701b0316905060006001600160a01b03881615612fba576040516370a0823160e01b81526001600160a01b038916906370a0823190612f74903090600401614bc1565b602060405180830381865afa158015612f91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fb59190615682565b612fbc565b475b9050818110612fd457612fd0888b846137e9565b8892505b50505b6000612fe38289615d8a565b90508015611d2e57612ff88988838989613272565b5050505050505050505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152506040805160e0810182526001600160a01b03928316815260075483166020820152600654909216908201526005546001600160401b03600160501b82048116606084015262010000820416608083015260ff80821660a08401526101009091041660c082015290565b60008060006130b6846138ab565b90506000604051602001613121907f454950373132446f6d61696e28737472696e67206e616d652c737472696e672081527f76657273696f6e2c75696e7432353620636861696e49642c627974657333322060208201526473616c742960d81b604082015260450190565b60408051601f1981840301815282825280516020918201208383018352600e84526d4f72696f6e2045786368616e676560901b93820193909352815180830183526001808252603160f81b918301919091528251808301949094527fabed71ea2445a13c99e4e4afa62b708e9aaf6cd13041ba86482e6cbf83fbc4cf848401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606085015260808401527ff2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a55760a0808501919091528251808503909101815260c08401835280519082012061190160f01b60e085015260e284015261010280840186905282518085039091018152610122909301909152815191012085516101608701519192506001600160a01b03169061325d908390613a39565b6001600160a01b031614959194509092505050565b6001600160a01b0380861660009081526020848152604080832093881683529290529081205460170b816132a68683615dc9565b9050600086121580156132b95750818112155b806132ce57506000861280156132ce57508181125b6132ea5760405162461bcd60e51b81526004016113ae90615e0a565b6000861380156132fa5750600082125b156133115761330c8888868985613576565b613386565b600082121580156133225750600081125b15613386576001600160a01b038716156133595761334c8761334683600019615d05565b8a613a5d565b6133569082615dc9565b90505b600081121561336e5761330c88888387613b87565b6000821361337d576001613380565b60005b60ff1692505b808214613466576001600160bf1b031981128015906133ac57506001600160bf1b038113155b6133c85760405162461bcd60e51b81526004016113ae90615e0a565b6001600160a01b03808916600090815260208781526040808320938b168352929052908120546133fb9060170b8361550c565b6001600160a01b038a8116600090815260208981526040808320938d16835292905281902080546001600160c01b0319166001600160c01b03861617905551909150600080516020615f3e8339815191529061345c908b908b90859061557f565b60405180910390a1505b505095945050505050565b603a54610100900460ff166134985760405162461bcd60e51b81526004016113ae90615bad565b61130c336128a6565b60006134f6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613c639092919063ffffffff16565b90508051600014806135175750808060200190518101906135179190615e27565b61158c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016113ae565b60008160170b126135915761358c858585613c7a565b61187d565b6001600160a01b0385166000908152602084905260408120545b6135b66001826154a8565b82101561361d576001600160a01b038781166000908152602087905260409020805491881691849081106135ec576135ec615720565b60009182526020909120600290910201546001600160a01b03161461361d578161361581615753565b9250506135ab565b6001600160a01b038716600090815260208690526040812080548490811061364757613647615720565b6000918252602090912060029091020160018101549091506001600160c01b03166001600160701b038616106136c9576136808461555c565b6001820180546001600160c01b0319166001600160c01b03929092169190911790558054600160a01b600160e01b031916600160a01b426001600160401b031602178155610bd4565b6001810180546001600160701b03871691906000906136f29084906001600160c01b0316615e42565b92506101000a8154816001600160c01b0302191690836001600160c01b031602179055505050505050505050565b600061228f828461576c565b600061228f828461578b565b6000806001600160a01b03841661376357612b3a6305f5e100612b3485670de0b6b3a7640000613720565b6000846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c79190615bf8565b60ff169050612bc66305f5e100612b346137e284600a615cf9565b8790613720565b801561158c576137f883613e5d565b15613897578047101561381e57604051631e9acf1760e31b815260040160405180910390fd5b6000826001600160a01b03168261138890604051600060405180830381858888f193505050503d8060008114613870576040519150601f19603f3d011682016040523d82523d6000602084013e613875565b606091505b5050905080611c295760405163b12d13eb60e01b815260040160405180910390fd5b61158c6001600160a01b0384168383612c06565b60006040516020016139b1907f4f7264657228616464726573732073656e646572416464726573732c6164647281527f657373206d617463686572416464726573732c6164647265737320626173654160208201527f737365742c616464726573732071756f746541737365742c616464726573732060408201527f6d61746368657246656541737365742c75696e74363420616d6f756e742c756960608201527f6e7436342070726963652c75696e743634206d6174636865724665652c75696e60808201527f743634206e6f6e63652c75696e7436342065787069726174696f6e2c75696e7460a0820152693820627579536964652960b01b60c082015260ca0190565b60405160208183030381529060405280519060200120826000015183602001518460400151856060015186608001518760a001518860c001518960e001518a61010001518b61012001518c6101400151604051602001613a1c9c9b9a99989796959493929190615e6a565b604051602081830303815290604052805190602001209050919050565b6000806000613a488585613e96565b91509150613a5581613edb565b509392505050565b600080613a6a8585613738565b6001600160701b0316905080856001600160a01b03166370a08231856040518263ffffffff1660e01b8152600401613aa29190614bc1565b602060405180830381865afa158015613abf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae39190615682565b10158015613b625750604051636eb1769f60e11b81526001600160a01b03848116600483015230602483015282919087169063dd62ed3e90604401602060405180830381865afa158015613b3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b5f9190615682565b10155b15613b7c57613b7385843084612936565b8391505061228f565b506000949350505050565b806000856001600160a01b03166001600160a01b031681526020019081526020016000206040518060600160405280856001600160a01b03168152602001426001600160401b0316815260200184613bde9061555c565b6001600160c01b03908116909152825460018181018555600094855260209485902084516002909302018054958501516001600160401b0316600160a01b026001600160e01b03199096166001600160a01b0390931692909217949094178155604090920151919092018054919092166001600160c01b031990911617905550505050565b6060613c728484600085614020565b949350505050565b6001600160a01b038316600090815260208290526040812054905b8181101561187d576001600160a01b03858116600090815260208590526040902080549186169183908110613ccc57613ccc615720565b60009182526020909120600290910201546001600160a01b031603613e4b576001821115613de9576001600160a01b0385166000908152602084905260409020613d176001846154a8565b81548110613d2757613d27615720565b9060005260206000209060020201836000876001600160a01b03166001600160a01b031681526020019081526020016000208281548110613d6a57613d6a615720565b60009182526020909120825460029092020180546001600160a01b031981166001600160a01b03909316928317825583546001600160401b03600160a01b9182900416026001600160e01b0319909116909217919091178155600191820154910180546001600160c01b0319166001600160c01b039092169190911790555b6001600160a01b0385166000908152602084905260409020805480613e1057613e10615ef8565b60008281526020902060026000199092019182020180546001600160e01b031916815560010180546001600160c01b0319169055905561187d565b80613e5581615753565b915050613c95565b60006001600160a01b0382161580611ece57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b6000808251604103613ecc5760208301516040840151606085015160001a613ec0878285856140fb565b94509450505050613ed4565b506000905060025b9250929050565b6000816004811115613eef57613eef6150f7565b03613ef75750565b6001816004811115613f0b57613f0b6150f7565b03613f535760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b60448201526064016113ae565b6002816004811115613f6757613f676150f7565b03613fb45760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016113ae565b6003816004811115613fc857613fc86150f7565b036112f75760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016113ae565b6060824710156140815760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016113ae565b600080866001600160a01b0316858760405161409d9190615f0e565b60006040518083038185875af1925050503d80600081146140da576040519150601f19603f3d011682016040523d82523d6000602084013e6140df565b606091505b50915091506140f0878383876141b5565b979650505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b0383111561412857506000905060036141ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561417c573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166141a5576000600192509250506141ac565b9150600090505b94509492505050565b6060831561422257825160000361421b576141cf856128f8565b61421b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016113ae565b5081613c72565b613c7283838151156142375781518083602001fd5b8060405162461bcd60e51b81526004016113ae9190615f2a565b8280548282559060005260206000209081019282156142a4579160200282015b828111156142a45781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190614271565b506142b09291506142b4565b5090565b5b808211156142b057600081556001016142b5565b6001600160401b03169052565b6001600160a01b03811681146112f757600080fd5b80356142f6816142d6565b919050565b634e487b7160e01b600052604160045260246000fd5b60405161018081016001600160401b0381118282101715614334576143346142fb565b60405290565b604051606081016001600160401b0381118282101715614334576143346142fb565b604051601f8201601f191681016001600160401b0381118282101715614384576143846142fb565b604052919050565b600060e0828403121561439e57600080fd5b60405160e081016001600160401b03811182821017156143c0576143c06142fb565b60405290508082356143d1816142d6565b815260208301356143e1816142d6565b602082015260408301356143f4816142d6565b60408201526060830135614407816142d6565b806060830152506080830135608082015260a083013560a082015260c083013560c08201525092915050565b60008083601f84011261444557600080fd5b5081356001600160401b0381111561445c57600080fd5b602083019150836020828501011115613ed457600080fd5b600080600080600080610140878903121561448e57600080fd5b8635614499816142d6565b95506144a8886020890161438c565b94506101008701356001600160401b03808211156144c557600080fd5b6144d18a838b01614433565b90965094506101208901359150808211156144eb57600080fd5b506144f889828a01614433565b979a9699509497509295939492505050565b80356001600160401b03811681146142f657600080fd5b60ff811681146112f757600080fd5b80356142f681614521565b600082601f83011261454c57600080fd5b81356001600160401b03811115614565576145656142fb565b614578601f8201601f191660200161435c565b81815284602083860101111561458d57600080fd5b816020850160208301376000918101602001919091529392505050565b600061018082840312156145bd57600080fd5b6145c5614311565b90506145d0826142eb565b81526145de602083016142eb565b60208201526145ef604083016142eb565b6040820152614600606083016142eb565b6060820152614611608083016142eb565b608082015261462260a0830161450a565b60a082015261463360c0830161450a565b60c082015261464460e0830161450a565b60e082015261010061465781840161450a565b9082015261012061466983820161450a565b9082015261014061467b838201614530565b90820152610160828101356001600160401b0381111561469a57600080fd5b6146a68582860161453b565b82840152505092915050565b803562ffffff811681146142f657600080fd5b600080600080600060a086880312156146dd57600080fd5b85356001600160401b03808211156146f457600080fd5b908701906060828a03121561470857600080fd5b61471061433a565b82358281111561471f57600080fd5b61472b8b8286016145aa565b82525061473a602084016146b2565b60208201526040830135604082015280975050602088013591508082111561476157600080fd5b5061476e888289016145aa565b94505061477d6040870161450a565b925061478b6060870161450a565b91506147996080870161450a565b90509295509295909350565b600061010082840312156147b857600080fd5b50919050565b6000806000604084860312156147d357600080fd5b83356001600160401b03808211156147ea57600080fd5b6147f6878388016147a5565b9450602086013591508082111561480c57600080fd5b5061481986828701614433565b9497909650939450505050565b80356001600160701b03811681146142f657600080fd5b600080600080600080600080610180808a8c03121561485b57600080fd5b6148648a614826565b985060208a01356001600160401b038082111561488057600080fd5b818c01915082828e03121561489457600080fd5b81995060408c013592506148a7836142d6565b8298506148b78d60608e0161438c565b97506101408c01359250808311156148ce57600080fd5b6148da8d848e01614433565b90975095506101608c01359250869150808311156148f757600080fd5b50506149058b828c01614433565b999c989b5096995094979396929594505050565b6000806000806000806080878903121561493257600080fd5b86356001600160401b038082111561494957600080fd5b6149558a838b016147a5565b9750602089013591508082111561496b57600080fd5b6149778a838b01614433565b9097509550604089013591508082111561499057600080fd5b61499c8a838b016147a5565b945060608901359150808211156144eb57600080fd5b6000602082840312156149c457600080fd5b5035919050565b6000602082840312156149dd57600080fd5b61228f8261450a565b6000602082840312156149f857600080fd5b813561228f816142d6565b600080600080600060608688031215614a1b57600080fd5b8535614a26816142d6565b945060208601356001600160401b0380821115614a4257600080fd5b614a4e89838a01614433565b90965094506040880135915080821115614a6757600080fd5b50614a7488828901614433565b969995985093965092949392505050565b600060c08284031215614a9757600080fd5b60405160c081016001600160401b0381118282101715614ab957614ab96142fb565b6040529050808235614aca816142d6565b8152614ad86020840161450a565b60208201526040830135614aeb816142d6565b6040820152614afc6060840161450a565b6060820152614b0d608084016146b2565b608082015260a083013560a08201525092915050565b600060c08284031215614b3557600080fd5b61228f8383614a85565b60008060408385031215614b5257600080fd5b8235614b5d816142d6565b915061192e60208401614826565b600080600060608486031215614b8057600080fd5b8335614b8b816142d6565b9250614b9960208501614826565b91506040840135614ba9816142d6565b809150509250925092565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b60008083601f840112614be757600080fd5b5081356001600160401b03811115614bfe57600080fd5b6020830191508360208260051b8501011115613ed457600080fd5b60008060008060408587031215614c2f57600080fd5b84356001600160401b0380821115614c4657600080fd5b614c5288838901614bd5565b90965094506020870135915080821115614c6b57600080fd5b50614c7887828801614bd5565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b81811015614cc55783516001600160a01b031683529284019291840191600101614ca0565b50909695505050505050565b60008060408385031215614ce457600080fd5b8235915060208301356001600160401b03811115614d0157600080fd5b614d0d858286016145aa565b9150509250929050565b60008060008060808587031215614d2d57600080fd5b84356001600160401b0380821115614d4457600080fd5b614d50888389016145aa565b95506020870135915080821115614d6657600080fd5b50614d73878288016145aa565b935050614d826040860161450a565b9150614d9060608601614826565b905092959194509250565b60008060008060808587031215614db157600080fd5b8435614dbc816142d6565b93506020850135614dcc816142d6565b92506040850135614d82816142d6565b60008060408385031215614def57600080fd5b82356001600160401b0380821115614e0657600080fd5b818501915085601f830112614e1a57600080fd5b8135602082821115614e2e57614e2e6142fb565b8160051b9250614e3f81840161435c565b8281529284018101928181019089851115614e5957600080fd5b948201945b84861015614e835785359350614e73846142d6565b8382529482019490820190614e5e565b9650614e9290508782016142eb565b9450505050509250929050565b6020808252825182820181905260009190848201906040850190845b81811015614cc557835160170b83529284019291840191600101614ebb565b60008060408385031215614eed57600080fd5b8235614ef8816142d6565b91506020830135614f08816142d6565b809150509250929050565b60008060008060008060a08789031215614f2c57600080fd5b86356001600160401b03811115614f4257600080fd5b614f4e89828a01614bd5565b9097509550506020870135614f6281614521565b93506040870135614f7281614521565b9250614f806060880161450a565b9150614f8e6080880161450a565b90509295509295509295565b60008060008060808587031215614fb057600080fd5b8435614fbb816142d6565b93506020850135614fcb816142d6565b92506040850135614fdb816142d6565b91506060850135614feb816142d6565b939692955090935050565b60006020828403121561500857600080fd5b81356001600160401b0381111561501e57600080fd5b613c72848285016145aa565b60008060e0838503121561503d57600080fd5b8235615048816142d6565b915061192e8460208501614a85565b602080825282518282018190526000919060409081850190868401855b828110156150be57815180516001600160a01b03168552868101516001600160401b0316878601528501516001600160c01b03168585015260609093019290850190600101615074565b5091979650505050505050565b600080604083850312156150de57600080fd5b82356150e9816142d6565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b815160808201906005811061513257634e487b7160e01b600052602160045260246000fd5b8083525060208301516020830152604083015160408301526060830151606083015292915050565b60018060a01b03808251168352806020830151166020840152806040830151166040840152806060830151166060840152506080810151608083015260a081015160a083015260c081015160c08301525050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b038716815260006101606151f5602084018961515a565b8061010084015261520981840187896151ae565b61012084019590955250506101400152949350505050565b6001600160a01b038681168252851660208201526000610140615247604084018761515a565b8061012084015261525b81840185876151ae565b98975050505050505050565b60008060006060848603121561527c57600080fd5b8351925060208401519150604084015190509250925092565b634e487b7160e01b600052601160045260246000fd5b60006001600160401b03828116848216811515828404821116156152d1576152d1615295565b02949350505050565b634e487b7160e01b600052601260045260246000fd5b60006001600160401b038381168061530a5761530a6152da565b92169190910492915050565b6000808335601e1984360301811261532d57600080fd5b83016020810192503590506001600160401b0381111561534c57600080fd5b803603821315613ed457600080fd5b60a081526000873561536c816142d6565b6001600160a01b031660a0830152615386602089016142eb565b61539360c0840182614bb4565b506153a0604089016142eb565b6153ad60e0840182614bb4565b506153ba606089016142eb565b6101006153c981850183614bb4565b6153d560808b0161450a565b91506153e56101208501836142c9565b6153f160a08b0161450a565b91506154016101408501836142c9565b60c08a013561016085015261541960e08b018b615316565b9250816101808601526154316101a0860184836151ae565b92505050828103602084015261544881888a6151ae565b6040840196909652505060608101929092526080909101529392505050565b6001600160a01b0386811682528581166020830152841660408201526080606082018190526000906140f090830184866151ae565b6000611ece36836145aa565b6000828210156154ba576154ba615295565b500390565b8681526001600160a01b0386811660208301528516604082015260006101606154eb606084018761515a565b806101408401526154ff81840185876151ae565b9998505050505050505050565b6000601782810b9084900b82811280156001600160bf1b031983018412161561553757615537615295565b6001600160bf1b038201831381161561555257615552615295565b5090039392505050565b6000601782900b600160bf1b810161557657615576615295565b60000392915050565b6001600160a01b03938416815291909216602082015260179190910b604082015260600190565b60006001600160401b038281168482168083038211156155c8576155c8615295565b01949350505050565b6000601782810b9084900b82821280156001600160bf1b03849003831316156155fc576155fc615295565b6001600160bf1b0319839003821281161561561957615619615295565b50019392505050565b600060018060a01b03808c16835260e0602084015261564560e084018b8d6151ae565b8381036040850152615658818a8c6151ae565b9790911660608401525050608081019390935260a083019190915260c09091015295945050505050565b60006020828403121561569457600080fd5b5051919050565b6001600160a01b038581168252841660208201526060604082018190526000906156c890830184866151ae565b9695505050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b92151583526001600160701b039190911660208301526001600160401b0316604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561574857600080fd5b813561228f81614521565b60006001820161576557615765615295565b5060010190565b600081600019048311821515161561578657615786615295565b500290565b60008261579a5761579a6152da565b500490565b60005b838110156157ba5781810151838201526020016157a2565b83811115611c295750506000910152565b600081518084526157e381602086016020860161579f565b601f01601f19169290920160200192915050565b6000610180615807848451614bb4565b60208301516158196020860182614bb4565b50604083015161582c6040860182614bb4565b50606083015161583f6060860182614bb4565b5060808301516158526080860182614bb4565b5060a083015161586560a08601826142c9565b5060c083015161587860c08601826142c9565b5060e083015161588b60e08601826142c9565b506101008084015161589f828701826142c9565b5050610120808401516158b4828701826142c9565b50506101408381015160ff1690850152610160808401518186018390526156c8838701826157cb565b60e0815260006158f060e083018a6157f7565b8281036020840152615902818a6157f7565b6001600160a01b0398891660408501526001600160701b0397909716606084015250506001600160401b0393909316608084015260a083019190915290921660c09092019190915292915050565b6000806040838503121561596357600080fd5b505080516020909101519092909150565b60018060a01b0380825116835280602083015116602084015280604083015116604084015250606081015160018060401b038082166060850152806080840151166080850152505060ff60a08201511660a083015260ff60c08201511660c08301525050565b60006101c082019050898252886020830152876040830152866060830152615a056080830187615974565b6001600160a01b03948516610160830152929093166101808401526001600160701b03166101a09092019190915295945050505050565b60208152600061228f60208301846157f7565b805180151581146142f657600080fd5b60008060408385031215615a7257600080fd5b615a7b83615a4f565b9150602083015190509250929050565b6000610160820190508682528560208301528460408301528360608301526156c86080830184615974565b600060808284031215615ac857600080fd5b604051608081016001600160401b0381118282101715615aea57615aea6142fb565b604052825160058110615afc57600080fd5b808252506020830151602082015260408301516040820152606083015160608201528091505092915050565b6020808252600490820152634533417360e01b604082015260600190565b6020808252600f908201526e125b98dbdc9c9958dd105b5bdd5b9d608a1b604082015260600190565b6000600160ff1b8201615b8457615b84615295565b5060000390565b60006001600160c01b038281168482168083038211156155c8576155c8615295565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600060208284031215615c0a57600080fd5b815161228f81614521565b600181815b80851115615c50578160001904821115615c3657615c36615295565b80851615615c4357918102915b93841c9390800290615c1a565b509250929050565b600082615c6757506001611ece565b81615c7457506000611ece565b8160018114615c8a5760028114615c9457615cb0565b6001915050611ece565b60ff841115615ca557615ca5615295565b50506001821b611ece565b5060208310610133831016604e8410600b8410161715615cd3575081810a611ece565b615cdd8383615c15565b8060001904821115615cf157615cf1615295565b029392505050565b600061228f8383615c58565b60006001600160ff1b0381841382841380821686840486111615615d2b57615d2b615295565b600160ff1b6000871282811687830589121615615d4a57615d4a615295565b60008712925087820587128484161615615d6657615d66615295565b87850587128184161615615d7c57615d7c615295565b505050929093029392505050565b60008083128015600160ff1b850184121615615da857615da8615295565b6001600160ff1b0384018313811615615dc357615dc3615295565b50500390565b600080821280156001600160ff1b0384900385131615615deb57615deb615295565b600160ff1b8390038412811615615e0457615e04615295565b50500190565b60208082526003908201526245313160e81b604082015260600190565b600060208284031215615e3957600080fd5b61228f82615a4f565b60006001600160c01b0383811690831681811015615e6257615e62615295565b039392505050565b8c81526001600160a01b038c811660208301528b811660408301528a811660608301528981166080830152881660a08201526001600160401b0387811660c083015286811660e083015285166101008201526101808101615ecf6101208301866142c9565b615edd6101408301856142c9565b60ff83166101608301529d9c50505050505050505050505050565b634e487b7160e01b600052603160045260246000fd5b60008251615f2081846020870161579f565b9190910192915050565b60208152600061228f60208301846157cb56fe2210a3e9136294756a7a989c32de6a75280c32dafeccc1280adcc9bb469f44a3565d6850cdd88f91fbcedecc61c18940ca739db2f1a27fc66ac9d4b236db81b8a26469706673582212202a3e234e5fdafae8c139081886d76210ecc5dd17e3d18f6f58b16b1039c5524764736f6c634300080f0033
Deployed Bytecode
0x6080604052600436106102065760003560e01c806311fbc3091461025357806312aa3caf1461029657806315ba55e5146102c457806318044e80146102e4578063253d73a81461030457806328d0a326146103245780632b3a54411461034b57806340f1a34d1461036b5780634e91d2c6146103b9578063548dd437146103d957806355664d37146103ee5780636241d7681461043b57806362a3f4dd1461047d5780636628b4641461049d5780636c3175bb146104bd578063715018a6146104d05780638129fc1c146104e55780638293e9af146104ed5780638795e1bb1461050d57806388a0ec621461052d5780638da5cb5b1461054d578063963ad20c1461056f578063a02fbb781461058f578063a0a90856146105af578063a1ff9bee1461066f578063a5ffc19a14610691578063a9d5ec76146106cb578063ad5c4648146106eb578063b0d3b87e1461070b578063b760faf91461072b578063c18c9d931461073e578063d0e30db01461076e578063d1c0702814610776578063d4fac45d146107a3578063dcffd7cb146107d6578063e0c3ebcf146107f0578063e326dbbf14610810578063e4fd7d0114610830578063e658defb14610850578063e6b8b82514610870578063ef74e5941461088f578063f2fde38b146108bf578063f721599e146108df578063f7522af61461090c578063ff782d9b146109625761022d565b3661022d5732330361022b57604051631b10b0f960e01b815260040160405180910390fd5b005b34801561023957600080fd5b506040516314ad190f60e21b815260040160405180910390fd5b34801561025f57600080fd5b50600554610279906201000090046001600160401b031681565b6040516001600160401b0390911681526020015b60405180910390f35b6102a96102a4366004614474565b61098f565b6040805193845260208401929092529082015260600161028d565b3480156102d057600080fd5b5061022b6102df3660046146c5565b610ad1565b3480156102f057600080fd5b5061022b6102ff3660046147be565b610bde565b34801561031057600080fd5b5061022b61031f36600461483d565b610cef565b34801561033057600080fd5b5060055461027990600160501b90046001600160401b031681565b34801561035757600080fd5b5061022b610366366004614919565b610ee4565b34801561037757600080fd5b506103a16103863660046149b2565b6000602081905290815260409020546001600160c01b031681565b6040516001600160c01b03909116815260200161028d565b3480156103c557600080fd5b5061022b6103d43660046149cb565b610f02565b3480156103e557600080fd5b5061022b611056565b3480156103fa57600080fd5b5061042d6104093660046149e6565b6001600160a01b03166000908152609f60205260409020546001600160401b031690565b60405190815260200161028d565b34801561044757600080fd5b5061046b6104563660046149e6565b60046020526000908152604090205460ff1681565b60405160ff909116815260200161028d565b34801561048957600080fd5b5061022b610498366004614a03565b61111c565b3480156104a957600080fd5b5061022b6104b83660046149b2565b61120d565b61022b6104cb366004614b23565b6112ed565b3480156104dc57600080fd5b5061022b6112fa565b61022b61130e565b3480156104f957600080fd5b5061022b610508366004614b3f565b61142a565b34801561051957600080fd5b5061022b610528366004614b6b565b611439565b34801561053957600080fd5b5061022b610548366004614b3f565b611591565b34801561055957600080fd5b5061056261159c565b60405161028d9190614bc1565b34801561057b57600080fd5b5061022b61058a366004614b6b565b6115ab565b34801561059b57600080fd5b5061022b6105aa366004614c19565b6117db565b3480156105bb57600080fd5b506106216105ca3660046149b2565b60a360205260009081526040902080546001909101546001600160a01b03808316926001600160401b03600160a01b80830482169460ff600160e01b9485900416948116939181049092169162ffffff9190041686565b604080516001600160a01b0397881681526001600160401b0396871660208201529415159085015294909116606083015291909116608082015262ffffff90911660a082015260c00161028d565b34801561067b57600080fd5b50610684611884565b60405161028d9190614c84565b34801561069d57600080fd5b506106b16106ac366004614cd1565b6118e6565b60408051601793840b81529190920b60208201520161028d565b3480156106d757600080fd5b5061022b6106e6366004614d17565b611937565b3480156106f757600080fd5b5060a254610562906001600160a01b031681565b34801561071757600080fd5b5061022b610726366004614d9b565b611c2f565b61022b6107393660046149e6565b611d3a565b34801561074a57600080fd5b5061075e6107593660046149e6565b611d58565b604051901515815260200161028d565b61022b611da3565b34801561078257600080fd5b50610796610791366004614ddc565b611dac565b60405161028d9190614e9f565b3480156107af57600080fd5b506107c36107be366004614eda565b611ea4565b60405160179190910b815260200161028d565b3480156107e257600080fd5b5060055461046b9060ff1681565b3480156107fc57600080fd5b5061022b61080b366004614f13565b611ed4565b34801561081c57600080fd5b5061022b61082b366004614f9a565b611f4a565b34801561083c57600080fd5b5061075e61084b366004614ff6565b611fa2565b34801561085c57600080fd5b5061022b61086b36600461502a565b61201c565b34801561087c57600080fd5b5060055461046b90610100900460ff1681565b34801561089b57600080fd5b5061075e6108aa3660046149b2565b60a46020526000908152604090205460ff1681565b3480156108cb57600080fd5b5061022b6108da3660046149e6565b612051565b3480156108eb57600080fd5b506108ff6108fa3660046149e6565b6120c7565b60405161028d9190615057565b34801561091857600080fd5b5061092c6109273660046150cb565b612173565b604080516001600160a01b0390941684526001600160401b0390921660208401526001600160c01b03169082015260600161028d565b34801561096e57600080fd5b5061098261097d3660046149e6565b6121d2565b60405161028d919061510d565b600080600061099c612296565b8760a001516000036109c1576040516328ebf24760e01b815260040160405180910390fd5b604051632c1affb960e01b8152734a7aa0fcf9b35d87b4125c90484497bb2e050e8590632c1affb990610a049033908c908c908c906001906002906004016151d7565b60006040518083038186803b158015610a1c57600080fd5b505af4158015610a30573d6000803e3d6000fd5b5050604051632da073a160e01b8152734a7aa0fcf9b35d87b4125c90484497bb2e050e859250632da073a19150610a739033908d908d908b908b90600401615221565b606060405180830381865af4158015610a90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab49190615267565b91945092509050610ac56001603955565b96509650969350505050565b6008546001600160a01b03163314610afc576040516387ece76560e01b815260040160405180910390fd5b6000808660000151610140015160ff16600103610b38578651610b2a9087876001600160401b038816611937565b505084516040015182610b75565b610b5186886000015187876001600160401b0316611937565b86516060015191506305f5e100610b6886866152ab565b610b7291906152f0565b90505b6040805160c08101825288516020908101516001600160a01b0390811683526001600160401b0380881683850152908616838501528416606083015289015162ffffff1660808201529088015160a0820152875151610bd490826122ef565b5050505050505050565b604051634a3e552760e11b81527359723329a1e906629516b30ca9c30400b11a1ecd9063947caa4e90610c229086908690869060a49060019060029060040161535b565b60006040518083038186803b158015610c3a57600080fd5b505af4158015610c4e573d6000803e3d6000fd5b50610c64925061075991505060208501856149e6565b610c815760405163188da0b360e21b815260040160405180910390fd5b7f62d93a8b1423235bfd6a4737b2e2069ee7c9ef53c8dab794a345f4d988d3f7e5610caf60208501856149e6565b610cbf60408601602087016149e6565b610ccf60808701606088016149e6565b8585604051610ce2959493929190615467565b60405180910390a1505050565b6008546001600160a01b03163314610d1a576040516387ece76560e01b815260040160405180910390fd5b610d22612296565b6000610d41610d308961549c565b878b6001600160701b031642612441565b9050610d5360a0890160808a016149e6565b6001600160a01b031686602001516001600160a01b031614610d8557610d80610d7b8961549c565b612713565b610db4565b610d96610100890160e08a016149cb565b6001600160401b03168660a001818151610db091906154a8565b9052505b734a7aa0fcf9b35d87b4125c90484497bb2e050e85632c1affb9610ddb60208b018b6149e6565b888888600160026040518763ffffffff1660e01b8152600401610e03969594939291906151d7565b60006040518083038186803b158015610e1b57600080fd5b505af4158015610e2f573d6000803e3d6000fd5b50734a7aa0fcf9b35d87b4125c90484497bb2e050e85925063d5542b6b9150839050610e5e60208c018c6149e6565b8a8a88886040518763ffffffff1660e01b8152600401610e83969594939291906154bf565b60006040518083038186803b158015610e9b57600080fd5b505af4158015610eaf573d6000803e3d6000fd5b50505050610ed9818960a0016020810190610eca91906149cb565b6001600160401b03168b6127b6565b50610bd46001603955565b610eef868686610bde565b610efa838383610bde565b505050505050565b3360008181526001602090815260408083206006546001600160a01b031684529091529020546001600160401b038316601790810b91900b1215610f595760405163569d45cf60e11b815260040160405180910390fd5b6001600160a01b038082166000908152609f6020908152604080832060018352818420600654909516845293909152812080546001600160401b0386169290610fa690849060170b61550c565b82546001600160c01b039182166101009390930a928302919092021990911617905550600654600080516020615f3e8339815191529083906001600160a01b0316610ff96001600160401b03871661555c565b6040516110089392919061557f565b60405180910390a180548390829060009061102d9084906001600160401b03166155a6565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550505050565b336000818152609f602090815260408083208054600184528285206006546001600160a01b03168652909352908320805491936001600160401b039093169290916110a590849060170b6155d1565b82546001600160c01b039182166101009390930a9283029190920219909116179055506006548154604051600080516020615f3e833981519152926111039286926001600160a01b03909216916001600160401b039091169061557f565b60405180910390a180546001600160481b031916905550565b6008546040516321963ec160e01b81526000917359723329a1e906629516b30ca9c30400b11a1ecd916321963ec191611174918a918a918a918a918a916001600160a01b03169060a390600190600290600401615622565b602060405180830381865af4158015611191573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b59190615682565b60018101546040519192507fe4efc926785e8287f79fae88209e8625600f4493b87d12e6eff70d9eba5bc755916111fd9189916001600160a01b03909116908990899061569b565b60405180910390a1505050505050565b604051632f7f859560e01b81526004810182905260a3602482015260016044820152600260648201526000907359723329a1e906629516b30ca9c30400b11a1ecd90632f7f859590608401602060405180830381865af4158015611275573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112999190615682565b805460018201546040519293507faa0d989110241a1a8280e797bfec099d9846f91bf9b168fc911a329ad7fa0228926112e1926001600160a01b0390811692169086906156d2565b60405180910390a15050565b6112f733826122ef565b50565b611302612847565b61130c60006128a6565b565b603a54610100900460ff161580801561132e5750603a54600160ff909116105b8061134f575061133d306128f8565b15801561134f5750603a5460ff166001145b6113b75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b603a805460ff1916600117905580156113da57603a805461ff0019166101001790555b6113e2612907565b80156112f757603a805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b6114358282336115ab565b5050565b611441612296565b6040516370a0823160e01b81526000906001600160a01b038516906370a0823190611470903090600401614bc1565b602060405180830381865afa15801561148d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b19190615682565b90506114d16001600160a01b03851633306001600160701b038716612936565b6040516370a0823160e01b815281906001600160a01b038616906370a08231906114ff903090600401614bc1565b602060405180830381865afa15801561151c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115409190615682565b61154a91906154a8565b9050826001600160701b03168110156115765760405163569d45cf60e11b815260040160405180910390fd5b61158184828461298e565b5061158c6001603955565b505050565b611435828233611439565b606d546001600160a01b031690565b6115b3612296565b60006115c884846001600160701b0316612b09565b3360009081526001602090815260408083206001600160a01b0389168452909152812080549293506001600160701b0384169290919061160c90849060170b61550c565b92506101000a8154816001600160c01b03021916908360170b6001600160c01b03160217905550600080516020615f3e8339815191528285836001600160701b03166116579061555c565b6040516116669392919061557f565b60405180910390a13360009081526001602090815260408083206001600160a01b038816845290915281205460170b12156116b45760405163569d45cf60e11b815260040160405180910390fd5b6116bd82611d58565b6116da5760405163188da0b360e21b815260040160405180910390fd5b6001600160a01b03841661176b576000826001600160a01b0316846001600160701b031660405160006040518083038185875af1925050503d806000811461173e576040519150601f19603f3d011682016040523d82523d6000602084013e611743565b606091505b50509050806117655760405163569d45cf60e11b815260040160405180910390fd5b50611788565b6117886001600160a01b038516836001600160701b038616612c06565b836001600160a01b0316826001600160a01b0316336001600160a01b0316600080516020615f5e833981519152600085426040516117c8939291906156f6565b60405180910390a45061158c6001603955565b6117e3612847565b60005b8381101561187d5782828281811061180057611800615720565b90506020020160208101906118159190615736565b6004600087878581811061182b5761182b615720565b905060200201602081019061184091906149e6565b6001600160a01b031681526020810191909152604001600020805460ff191660ff929092169190911790558061187581615753565b9150506117e6565b5050505050565b606060038054806020026020016040519081016040528092919081815260200182805480156118dc57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116118be575b5050505050905090565b60008281526020819052604081205460a083015160e08401516001600160c01b0390921692916001600160401b03918216916119249185911661576c565b61192e919061578b565b90509250929050565b61193f612296565b60006305f5e1006119626001600160401b0385166001600160701b03851661576c565b61196c919061578b565b90506001600160701b03811061199557604051631a93c68960e11b815260040160405180910390fd5b60085460405163c956a3b760e01b81528291600091829173e8c2ac36f9e689f0b4b7c52d80b42fdfbd6645679163c956a3b7916119ec918c918c9133918c918e9142916001600160a01b03909116906004016158dd565b6040805180830381865af4158015611a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2c9190615950565b91509150611a48828960a001516001600160401b0316876127b6565b611a60818860a001516001600160401b0316876127b6565b611a8b6040518060800160405280600081526020016000815260200160008152602001600081525090565b611a9c898786600360016002612c36565b60408301528152611ab38887866002600181612c36565b6060830152602082015280518951604080840151908c0151611adb9392919060016002612e4a565b611afb8160200151896000015183606001518b6060015160016002612e4a565b8851611b0690611d58565b611b235760405163188da0b360e21b815260040160405180910390fd5b8751611b2e90611d58565b611b4b5760405163188da0b360e21b815260040160405180910390fd5b87600001516001600160a01b031689600001516001600160a01b03167f22aceb00bb2ded7eb0facc722fa061971f5950b739ecb216300e019b74ccd4a08b604001518c606001518b8b8a8a8a604051602001611bb1929190918252602082015260400190565b60408051601f1981840301815282825280516020918201206001600160a01b03988916845296909716968201969096526001600160401b0393909316838601526001600160701b03918216606084015216608082015260a081019190915290519081900360c00190a35050505050611c296001603955565b50505050565b6000805b600354811015611c8d57836001600160a01b031660038281548110611c5a57611c5a615720565b6000918252602090912001546001600160a01b031603611c7d5760019150611c8d565b611c8681615753565b9050611c33565b5080611cac5760405163a87fa00b60e01b815260040160405180910390fd5b6000611cb786613005565b6040516309f70f0560e31b815290915073dc91af7b038cc8760a0c53814f21be09caace0d790634fb8782890611d029060039060029060019060049088908d908d908d9085016159da565b60006040518083038186803b158015611d1a57600080fd5b505af4158015611d2e573d6000803e3d6000fd5b50505050505050505050565b611d42612296565b611d4e6000348361298e565b6112f76001603955565b6001600160a01b0381166000908152600260205260408120548103611d7f57506001919050565b6000611d8a836121d2565b516004811115611d9c57611d9c6150f7565b1492915050565b61130c33611d3a565b606082516001600160401b03811115611dc757611dc76142fb565b604051908082528060200260200182016040528015611df0578160200160208202803683370190505b50905060005b8351811015611e9d576001600160a01b03831660009081526001602052604081208551909190869084908110611e2e57611e2e615720565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900460170b828281518110611e7657611e76615720565b602002602001019060170b908160170b815250508080611e9590615753565b915050611df6565b5092915050565b6001600160a01b0380821660009081526001602090815260408083209386168352929052205460170b5b92915050565b611edc612847565b611ee860038787614251565b506005805460ff95861661ffff199091161761010094909516939093029390931762010000600160901b031916620100006001600160401b0392831602600160501b600160901b03191617600160501b93909116929092029190911790555050565b611f52612847565b600680546001600160a01b039586166001600160a01b0319918216179091556007805494861694821694909417909355600880549285169284169290921790915560a28054919093169116179055565b60405163e7e652ed60e01b815260009073e8c2ac36f9e689f0b4b7c52d80b42fdfbd6645679063e7e652ed90611fdc908590600401615a3c565b6040805180830381865af4158015611ff8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e9d9190615a5f565b6008546001600160a01b03163314612047576040516387ece76560e01b815260040160405180910390fd5b61143582826122ef565b612059612847565b6001600160a01b0381166120be5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016113ae565b6112f7816128a6565b6001600160a01b0381166000908152600260209081526040808320805482518185028101850190935280835260609492939192909184015b82821015612168576000848152602090819020604080516060810182526002860290920180546001600160a01b0381168452600160a01b90046001600160401b0316838501526001908101546001600160c01b03169183019190915290835290920191016120ff565b505050509050919050565b6002602052816000526040600020818154811061218f57600080fd5b6000918252602090912060029091020180546001909101546001600160a01b0382169350600160a01b9091046001600160401b031691506001600160c01b031683565b6121fe604080516080810190915280600081526020016000815260200160008152602001600081525090565b600061220983613005565b60405163f127baa160e01b815290915073dc91af7b038cc8760a0c53814f21be09caace0d79063f127baa19061224e9060039060029060019060049088908201615a8b565b608060405180830381865af415801561226b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228f9190615ab6565b9392505050565b6002603954036122e85760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016113ae565b6002603955565b6122f7612296565b6040805163c568f68560e01b81526001600160a01b03808516600483015283518116602483015260208401516001600160401b0390811660448401529284015116606482015260608301519091166084820152608082015162ffffff1660a482015260a082015160c482015260a360e4820152600161010482015260026101248201527359723329a1e906629516b30ca9c30400b11a1ecd9063c568f685906101440160006040518083038186803b1580156123b257600080fd5b505af41580156123c6573d6000803e3d6000fd5b505050506123d382611d58565b6123f05760405163188da0b360e21b815260040160405180910390fd5b7f8156ea5248573c664d8d0995ccb941c2cd87e2e6fa12d8a56594295bae8d14bb816000015182604001518360a0015160405161242f939291906156d2565b60405180910390a16114356001603955565b60008061244d866130a8565b92509050806124845760405162461bcd60e51b815260206004820152600360248201526222992160e91b60448201526064016113ae565b60006305f5e1008760c001516001600160401b0316866124a4919061576c565b6124ae919061578b565b905060008088610140015160ff1660010361252b5787600001516001600160a01b031689606001516001600160a01b0316148015612505575087602001516001600160a01b031689604001516001600160a01b0316145b6125215760405162461bcd60e51b81526004016113ae90615b28565b508190508561258f565b87600001516001600160a01b031689604001516001600160a01b031614801561256d575087602001516001600160a01b031689606001516001600160a01b0316145b6125895760405162461bcd60e51b81526004016113ae90615b28565b50859050815b87606001516001600160a01b031689600001516001600160a01b0316146125ec5760405162461bcd60e51b815260206004820152601160248201527024b731b7b93932b1ba2932b1b2b4bb32b960791b60448201526064016113ae565b8760800151821461260f5760405162461bcd60e51b81526004016113ae90615b46565b8760a001518110156126335760405162461bcd60e51b81526004016113ae90615b46565b8860a001516001600160401b03168711156126785760405162461bcd60e51b81526020600482015260056024820152642299a0b6a160d91b60448201526064016113ae565b856103e88a610120015161268c91906152f0565b6001600160401b031610156126c95760405162461bcd60e51b8152602060048201526003602482015262229a2160e91b60448201526064016113ae565b88608001516001600160a01b031688602001516001600160a01b031603612707578860e001516001600160401b03168860a001511161270757600080fd5b50505050949350505050565b612740816000015182608001518360e001516001600160401b031661273790615b6f565b60016002613272565b5080516001600160a01b039081166000908152600160209081526040808320608086015190941683529290529081205460170b121561279257604051631e9acf1760e31b815260040160405180910390fd5b611435816020015182608001518360e001516001600160401b031660016002613272565b6000838152602081905260409020546001600160c01b03166127e16001600160701b03831682615b8b565b9050826001600160c01b0316816001600160c01b03161115612816576040516341a26a6360e01b815260040160405180910390fd5b60009384526020849052604090932080546001600160c01b0319166001600160c01b03909416939093179092555050565b3361285061159c565b6001600160a01b03161461130c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016113ae565b606d80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b03163b151590565b603a54610100900460ff1661292e5760405162461bcd60e51b81526004016113ae90615bad565b61130c613471565b611c29846323b872dd60e01b858585604051602401612957939291906156d2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526134a1565b6001600160a01b03808216600090815260016020908152604080832093871683529290529081205460170b8113906129cf856001600160701b038616612b09565b6001600160a01b038085166000908152600160209081526040808320938a16835292905290812080549293506001600160701b03841692909190612a1790849060170b6155d1565b92506101000a8154816001600160c01b03021916908360170b6001600160c01b03160217905550600080516020615f3e8339815191528386836001600160701b0316604051612a689392919061557f565b60405180910390a16001600160701b03841615612ac857846001600160a01b0316836001600160a01b0316336001600160a01b0316600080516020615f5e83398151915260018542604051612abf939291906156f6565b60405180910390a45b811561187d576001600160a01b0380841660009081526001602090815260408083209389168352929052205461187d9084908790600290859060170b613576565b6000806001600160a01b038416612b4157612b3a670de0b6b3a7640000612b34856305f5e100613720565b9061372c565b9050612bca565b6000846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba59190615bf8565b60ff169050612bc6612bb882600a615cf9565b612b34866305f5e100613720565b9150505b60016001606f1b03811061228f5760405162461bcd60e51b815260206004820152600360248201526245335560e81b60448201526064016113ae565b6040516001600160a01b03831660248201526044810182905261158c90849063a9059cbb60e01b90606401612957565b60008060018516156002861615801590612c93578960a001516001600160401b0316896001600160701b03168b60e001516001600160401b0316612c7a919061576c565b612c84919061578b565b6001600160401b031660e08b01525b506001600160701b03881615612e3e5760408051608081018252600080825260208201819052918101829052606081019190915281612cf057612ce16001600160701b038916600019615d05565b896001600160701b0316612d10565b612d056001600160701b038a16600019615d05565b886001600160701b03165b6040830152815281612d2b5789606001518a60400151612d36565b89604001518a606001515b6001600160a01b0390811660608401529081166020830181905260808c01516001921603612d85578a60e001516001600160401b031682600001818151612d7d9190615d8a565b905250612df7565b81606001516001600160a01b03168b608001516001600160a01b031603612dc5578a60e001516001600160401b031682604001818151612d7d9190615d8a565b612df48b600001518c608001518d60e001516001600160401b0316600019612ded9190615d05565b8a8a613272565b90505b8a5160208301518351612e0d9291908a8a613272565b8116945081604001519350612e3a8b602001518c608001518d60e001516001600160401b03168a8a613272565b5050505b50965096945050505050565b6001600160a01b0380861660009081526020848152604080832093871683529290529081205460170b90612e7e8287615dc9565b905060008612158015612e915750818112155b80612ea65750600086128015612ea657508181125b612ec25760405162461bcd60e51b81526004016113ae90615e0a565b600088158015612ed957506001600160a01b038616155b8015612ef55750662386f26fc10000886001600160a01b031631105b15612eff57600198505b886001148015612f0f5750600087135b8015612f1b5750600082135b15612fd7576000612f2c8789613738565b6001600160701b0316905060006001600160a01b03881615612fba576040516370a0823160e01b81526001600160a01b038916906370a0823190612f74903090600401614bc1565b602060405180830381865afa158015612f91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fb59190615682565b612fbc565b475b9050818110612fd457612fd0888b846137e9565b8892505b50505b6000612fe38289615d8a565b90508015611d2e57612ff88988838989613272565b5050505050505050505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152506040805160e0810182526001600160a01b03928316815260075483166020820152600654909216908201526005546001600160401b03600160501b82048116606084015262010000820416608083015260ff80821660a08401526101009091041660c082015290565b60008060006130b6846138ab565b90506000604051602001613121907f454950373132446f6d61696e28737472696e67206e616d652c737472696e672081527f76657273696f6e2c75696e7432353620636861696e49642c627974657333322060208201526473616c742960d81b604082015260450190565b60408051601f1981840301815282825280516020918201208383018352600e84526d4f72696f6e2045786368616e676560901b93820193909352815180830183526001808252603160f81b918301919091528251808301949094527fabed71ea2445a13c99e4e4afa62b708e9aaf6cd13041ba86482e6cbf83fbc4cf848401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606085015260808401527ff2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a55760a0808501919091528251808503909101815260c08401835280519082012061190160f01b60e085015260e284015261010280840186905282518085039091018152610122909301909152815191012085516101608701519192506001600160a01b03169061325d908390613a39565b6001600160a01b031614959194509092505050565b6001600160a01b0380861660009081526020848152604080832093881683529290529081205460170b816132a68683615dc9565b9050600086121580156132b95750818112155b806132ce57506000861280156132ce57508181125b6132ea5760405162461bcd60e51b81526004016113ae90615e0a565b6000861380156132fa5750600082125b156133115761330c8888868985613576565b613386565b600082121580156133225750600081125b15613386576001600160a01b038716156133595761334c8761334683600019615d05565b8a613a5d565b6133569082615dc9565b90505b600081121561336e5761330c88888387613b87565b6000821361337d576001613380565b60005b60ff1692505b808214613466576001600160bf1b031981128015906133ac57506001600160bf1b038113155b6133c85760405162461bcd60e51b81526004016113ae90615e0a565b6001600160a01b03808916600090815260208781526040808320938b168352929052908120546133fb9060170b8361550c565b6001600160a01b038a8116600090815260208981526040808320938d16835292905281902080546001600160c01b0319166001600160c01b03861617905551909150600080516020615f3e8339815191529061345c908b908b90859061557f565b60405180910390a1505b505095945050505050565b603a54610100900460ff166134985760405162461bcd60e51b81526004016113ae90615bad565b61130c336128a6565b60006134f6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613c639092919063ffffffff16565b90508051600014806135175750808060200190518101906135179190615e27565b61158c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016113ae565b60008160170b126135915761358c858585613c7a565b61187d565b6001600160a01b0385166000908152602084905260408120545b6135b66001826154a8565b82101561361d576001600160a01b038781166000908152602087905260409020805491881691849081106135ec576135ec615720565b60009182526020909120600290910201546001600160a01b03161461361d578161361581615753565b9250506135ab565b6001600160a01b038716600090815260208690526040812080548490811061364757613647615720565b6000918252602090912060029091020160018101549091506001600160c01b03166001600160701b038616106136c9576136808461555c565b6001820180546001600160c01b0319166001600160c01b03929092169190911790558054600160a01b600160e01b031916600160a01b426001600160401b031602178155610bd4565b6001810180546001600160701b03871691906000906136f29084906001600160c01b0316615e42565b92506101000a8154816001600160c01b0302191690836001600160c01b031602179055505050505050505050565b600061228f828461576c565b600061228f828461578b565b6000806001600160a01b03841661376357612b3a6305f5e100612b3485670de0b6b3a7640000613720565b6000846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c79190615bf8565b60ff169050612bc66305f5e100612b346137e284600a615cf9565b8790613720565b801561158c576137f883613e5d565b15613897578047101561381e57604051631e9acf1760e31b815260040160405180910390fd5b6000826001600160a01b03168261138890604051600060405180830381858888f193505050503d8060008114613870576040519150601f19603f3d011682016040523d82523d6000602084013e613875565b606091505b5050905080611c295760405163b12d13eb60e01b815260040160405180910390fd5b61158c6001600160a01b0384168383612c06565b60006040516020016139b1907f4f7264657228616464726573732073656e646572416464726573732c6164647281527f657373206d617463686572416464726573732c6164647265737320626173654160208201527f737365742c616464726573732071756f746541737365742c616464726573732060408201527f6d61746368657246656541737365742c75696e74363420616d6f756e742c756960608201527f6e7436342070726963652c75696e743634206d6174636865724665652c75696e60808201527f743634206e6f6e63652c75696e7436342065787069726174696f6e2c75696e7460a0820152693820627579536964652960b01b60c082015260ca0190565b60405160208183030381529060405280519060200120826000015183602001518460400151856060015186608001518760a001518860c001518960e001518a61010001518b61012001518c6101400151604051602001613a1c9c9b9a99989796959493929190615e6a565b604051602081830303815290604052805190602001209050919050565b6000806000613a488585613e96565b91509150613a5581613edb565b509392505050565b600080613a6a8585613738565b6001600160701b0316905080856001600160a01b03166370a08231856040518263ffffffff1660e01b8152600401613aa29190614bc1565b602060405180830381865afa158015613abf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae39190615682565b10158015613b625750604051636eb1769f60e11b81526001600160a01b03848116600483015230602483015282919087169063dd62ed3e90604401602060405180830381865afa158015613b3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b5f9190615682565b10155b15613b7c57613b7385843084612936565b8391505061228f565b506000949350505050565b806000856001600160a01b03166001600160a01b031681526020019081526020016000206040518060600160405280856001600160a01b03168152602001426001600160401b0316815260200184613bde9061555c565b6001600160c01b03908116909152825460018181018555600094855260209485902084516002909302018054958501516001600160401b0316600160a01b026001600160e01b03199096166001600160a01b0390931692909217949094178155604090920151919092018054919092166001600160c01b031990911617905550505050565b6060613c728484600085614020565b949350505050565b6001600160a01b038316600090815260208290526040812054905b8181101561187d576001600160a01b03858116600090815260208590526040902080549186169183908110613ccc57613ccc615720565b60009182526020909120600290910201546001600160a01b031603613e4b576001821115613de9576001600160a01b0385166000908152602084905260409020613d176001846154a8565b81548110613d2757613d27615720565b9060005260206000209060020201836000876001600160a01b03166001600160a01b031681526020019081526020016000208281548110613d6a57613d6a615720565b60009182526020909120825460029092020180546001600160a01b031981166001600160a01b03909316928317825583546001600160401b03600160a01b9182900416026001600160e01b0319909116909217919091178155600191820154910180546001600160c01b0319166001600160c01b039092169190911790555b6001600160a01b0385166000908152602084905260409020805480613e1057613e10615ef8565b60008281526020902060026000199092019182020180546001600160e01b031916815560010180546001600160c01b0319169055905561187d565b80613e5581615753565b915050613c95565b60006001600160a01b0382161580611ece57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b6000808251604103613ecc5760208301516040840151606085015160001a613ec0878285856140fb565b94509450505050613ed4565b506000905060025b9250929050565b6000816004811115613eef57613eef6150f7565b03613ef75750565b6001816004811115613f0b57613f0b6150f7565b03613f535760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b60448201526064016113ae565b6002816004811115613f6757613f676150f7565b03613fb45760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016113ae565b6003816004811115613fc857613fc86150f7565b036112f75760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016113ae565b6060824710156140815760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016113ae565b600080866001600160a01b0316858760405161409d9190615f0e565b60006040518083038185875af1925050503d80600081146140da576040519150601f19603f3d011682016040523d82523d6000602084013e6140df565b606091505b50915091506140f0878383876141b5565b979650505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b0383111561412857506000905060036141ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561417c573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166141a5576000600192509250506141ac565b9150600090505b94509492505050565b6060831561422257825160000361421b576141cf856128f8565b61421b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016113ae565b5081613c72565b613c7283838151156142375781518083602001fd5b8060405162461bcd60e51b81526004016113ae9190615f2a565b8280548282559060005260206000209081019282156142a4579160200282015b828111156142a45781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190614271565b506142b09291506142b4565b5090565b5b808211156142b057600081556001016142b5565b6001600160401b03169052565b6001600160a01b03811681146112f757600080fd5b80356142f6816142d6565b919050565b634e487b7160e01b600052604160045260246000fd5b60405161018081016001600160401b0381118282101715614334576143346142fb565b60405290565b604051606081016001600160401b0381118282101715614334576143346142fb565b604051601f8201601f191681016001600160401b0381118282101715614384576143846142fb565b604052919050565b600060e0828403121561439e57600080fd5b60405160e081016001600160401b03811182821017156143c0576143c06142fb565b60405290508082356143d1816142d6565b815260208301356143e1816142d6565b602082015260408301356143f4816142d6565b60408201526060830135614407816142d6565b806060830152506080830135608082015260a083013560a082015260c083013560c08201525092915050565b60008083601f84011261444557600080fd5b5081356001600160401b0381111561445c57600080fd5b602083019150836020828501011115613ed457600080fd5b600080600080600080610140878903121561448e57600080fd5b8635614499816142d6565b95506144a8886020890161438c565b94506101008701356001600160401b03808211156144c557600080fd5b6144d18a838b01614433565b90965094506101208901359150808211156144eb57600080fd5b506144f889828a01614433565b979a9699509497509295939492505050565b80356001600160401b03811681146142f657600080fd5b60ff811681146112f757600080fd5b80356142f681614521565b600082601f83011261454c57600080fd5b81356001600160401b03811115614565576145656142fb565b614578601f8201601f191660200161435c565b81815284602083860101111561458d57600080fd5b816020850160208301376000918101602001919091529392505050565b600061018082840312156145bd57600080fd5b6145c5614311565b90506145d0826142eb565b81526145de602083016142eb565b60208201526145ef604083016142eb565b6040820152614600606083016142eb565b6060820152614611608083016142eb565b608082015261462260a0830161450a565b60a082015261463360c0830161450a565b60c082015261464460e0830161450a565b60e082015261010061465781840161450a565b9082015261012061466983820161450a565b9082015261014061467b838201614530565b90820152610160828101356001600160401b0381111561469a57600080fd5b6146a68582860161453b565b82840152505092915050565b803562ffffff811681146142f657600080fd5b600080600080600060a086880312156146dd57600080fd5b85356001600160401b03808211156146f457600080fd5b908701906060828a03121561470857600080fd5b61471061433a565b82358281111561471f57600080fd5b61472b8b8286016145aa565b82525061473a602084016146b2565b60208201526040830135604082015280975050602088013591508082111561476157600080fd5b5061476e888289016145aa565b94505061477d6040870161450a565b925061478b6060870161450a565b91506147996080870161450a565b90509295509295909350565b600061010082840312156147b857600080fd5b50919050565b6000806000604084860312156147d357600080fd5b83356001600160401b03808211156147ea57600080fd5b6147f6878388016147a5565b9450602086013591508082111561480c57600080fd5b5061481986828701614433565b9497909650939450505050565b80356001600160701b03811681146142f657600080fd5b600080600080600080600080610180808a8c03121561485b57600080fd5b6148648a614826565b985060208a01356001600160401b038082111561488057600080fd5b818c01915082828e03121561489457600080fd5b81995060408c013592506148a7836142d6565b8298506148b78d60608e0161438c565b97506101408c01359250808311156148ce57600080fd5b6148da8d848e01614433565b90975095506101608c01359250869150808311156148f757600080fd5b50506149058b828c01614433565b999c989b5096995094979396929594505050565b6000806000806000806080878903121561493257600080fd5b86356001600160401b038082111561494957600080fd5b6149558a838b016147a5565b9750602089013591508082111561496b57600080fd5b6149778a838b01614433565b9097509550604089013591508082111561499057600080fd5b61499c8a838b016147a5565b945060608901359150808211156144eb57600080fd5b6000602082840312156149c457600080fd5b5035919050565b6000602082840312156149dd57600080fd5b61228f8261450a565b6000602082840312156149f857600080fd5b813561228f816142d6565b600080600080600060608688031215614a1b57600080fd5b8535614a26816142d6565b945060208601356001600160401b0380821115614a4257600080fd5b614a4e89838a01614433565b90965094506040880135915080821115614a6757600080fd5b50614a7488828901614433565b969995985093965092949392505050565b600060c08284031215614a9757600080fd5b60405160c081016001600160401b0381118282101715614ab957614ab96142fb565b6040529050808235614aca816142d6565b8152614ad86020840161450a565b60208201526040830135614aeb816142d6565b6040820152614afc6060840161450a565b6060820152614b0d608084016146b2565b608082015260a083013560a08201525092915050565b600060c08284031215614b3557600080fd5b61228f8383614a85565b60008060408385031215614b5257600080fd5b8235614b5d816142d6565b915061192e60208401614826565b600080600060608486031215614b8057600080fd5b8335614b8b816142d6565b9250614b9960208501614826565b91506040840135614ba9816142d6565b809150509250925092565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b60008083601f840112614be757600080fd5b5081356001600160401b03811115614bfe57600080fd5b6020830191508360208260051b8501011115613ed457600080fd5b60008060008060408587031215614c2f57600080fd5b84356001600160401b0380821115614c4657600080fd5b614c5288838901614bd5565b90965094506020870135915080821115614c6b57600080fd5b50614c7887828801614bd5565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b81811015614cc55783516001600160a01b031683529284019291840191600101614ca0565b50909695505050505050565b60008060408385031215614ce457600080fd5b8235915060208301356001600160401b03811115614d0157600080fd5b614d0d858286016145aa565b9150509250929050565b60008060008060808587031215614d2d57600080fd5b84356001600160401b0380821115614d4457600080fd5b614d50888389016145aa565b95506020870135915080821115614d6657600080fd5b50614d73878288016145aa565b935050614d826040860161450a565b9150614d9060608601614826565b905092959194509250565b60008060008060808587031215614db157600080fd5b8435614dbc816142d6565b93506020850135614dcc816142d6565b92506040850135614d82816142d6565b60008060408385031215614def57600080fd5b82356001600160401b0380821115614e0657600080fd5b818501915085601f830112614e1a57600080fd5b8135602082821115614e2e57614e2e6142fb565b8160051b9250614e3f81840161435c565b8281529284018101928181019089851115614e5957600080fd5b948201945b84861015614e835785359350614e73846142d6565b8382529482019490820190614e5e565b9650614e9290508782016142eb565b9450505050509250929050565b6020808252825182820181905260009190848201906040850190845b81811015614cc557835160170b83529284019291840191600101614ebb565b60008060408385031215614eed57600080fd5b8235614ef8816142d6565b91506020830135614f08816142d6565b809150509250929050565b60008060008060008060a08789031215614f2c57600080fd5b86356001600160401b03811115614f4257600080fd5b614f4e89828a01614bd5565b9097509550506020870135614f6281614521565b93506040870135614f7281614521565b9250614f806060880161450a565b9150614f8e6080880161450a565b90509295509295509295565b60008060008060808587031215614fb057600080fd5b8435614fbb816142d6565b93506020850135614fcb816142d6565b92506040850135614fdb816142d6565b91506060850135614feb816142d6565b939692955090935050565b60006020828403121561500857600080fd5b81356001600160401b0381111561501e57600080fd5b613c72848285016145aa565b60008060e0838503121561503d57600080fd5b8235615048816142d6565b915061192e8460208501614a85565b602080825282518282018190526000919060409081850190868401855b828110156150be57815180516001600160a01b03168552868101516001600160401b0316878601528501516001600160c01b03168585015260609093019290850190600101615074565b5091979650505050505050565b600080604083850312156150de57600080fd5b82356150e9816142d6565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b815160808201906005811061513257634e487b7160e01b600052602160045260246000fd5b8083525060208301516020830152604083015160408301526060830151606083015292915050565b60018060a01b03808251168352806020830151166020840152806040830151166040840152806060830151166060840152506080810151608083015260a081015160a083015260c081015160c08301525050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b038716815260006101606151f5602084018961515a565b8061010084015261520981840187896151ae565b61012084019590955250506101400152949350505050565b6001600160a01b038681168252851660208201526000610140615247604084018761515a565b8061012084015261525b81840185876151ae565b98975050505050505050565b60008060006060848603121561527c57600080fd5b8351925060208401519150604084015190509250925092565b634e487b7160e01b600052601160045260246000fd5b60006001600160401b03828116848216811515828404821116156152d1576152d1615295565b02949350505050565b634e487b7160e01b600052601260045260246000fd5b60006001600160401b038381168061530a5761530a6152da565b92169190910492915050565b6000808335601e1984360301811261532d57600080fd5b83016020810192503590506001600160401b0381111561534c57600080fd5b803603821315613ed457600080fd5b60a081526000873561536c816142d6565b6001600160a01b031660a0830152615386602089016142eb565b61539360c0840182614bb4565b506153a0604089016142eb565b6153ad60e0840182614bb4565b506153ba606089016142eb565b6101006153c981850183614bb4565b6153d560808b0161450a565b91506153e56101208501836142c9565b6153f160a08b0161450a565b91506154016101408501836142c9565b60c08a013561016085015261541960e08b018b615316565b9250816101808601526154316101a0860184836151ae565b92505050828103602084015261544881888a6151ae565b6040840196909652505060608101929092526080909101529392505050565b6001600160a01b0386811682528581166020830152841660408201526080606082018190526000906140f090830184866151ae565b6000611ece36836145aa565b6000828210156154ba576154ba615295565b500390565b8681526001600160a01b0386811660208301528516604082015260006101606154eb606084018761515a565b806101408401526154ff81840185876151ae565b9998505050505050505050565b6000601782810b9084900b82811280156001600160bf1b031983018412161561553757615537615295565b6001600160bf1b038201831381161561555257615552615295565b5090039392505050565b6000601782900b600160bf1b810161557657615576615295565b60000392915050565b6001600160a01b03938416815291909216602082015260179190910b604082015260600190565b60006001600160401b038281168482168083038211156155c8576155c8615295565b01949350505050565b6000601782810b9084900b82821280156001600160bf1b03849003831316156155fc576155fc615295565b6001600160bf1b0319839003821281161561561957615619615295565b50019392505050565b600060018060a01b03808c16835260e0602084015261564560e084018b8d6151ae565b8381036040850152615658818a8c6151ae565b9790911660608401525050608081019390935260a083019190915260c09091015295945050505050565b60006020828403121561569457600080fd5b5051919050565b6001600160a01b038581168252841660208201526060604082018190526000906156c890830184866151ae565b9695505050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b92151583526001600160701b039190911660208301526001600160401b0316604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561574857600080fd5b813561228f81614521565b60006001820161576557615765615295565b5060010190565b600081600019048311821515161561578657615786615295565b500290565b60008261579a5761579a6152da565b500490565b60005b838110156157ba5781810151838201526020016157a2565b83811115611c295750506000910152565b600081518084526157e381602086016020860161579f565b601f01601f19169290920160200192915050565b6000610180615807848451614bb4565b60208301516158196020860182614bb4565b50604083015161582c6040860182614bb4565b50606083015161583f6060860182614bb4565b5060808301516158526080860182614bb4565b5060a083015161586560a08601826142c9565b5060c083015161587860c08601826142c9565b5060e083015161588b60e08601826142c9565b506101008084015161589f828701826142c9565b5050610120808401516158b4828701826142c9565b50506101408381015160ff1690850152610160808401518186018390526156c8838701826157cb565b60e0815260006158f060e083018a6157f7565b8281036020840152615902818a6157f7565b6001600160a01b0398891660408501526001600160701b0397909716606084015250506001600160401b0393909316608084015260a083019190915290921660c09092019190915292915050565b6000806040838503121561596357600080fd5b505080516020909101519092909150565b60018060a01b0380825116835280602083015116602084015280604083015116604084015250606081015160018060401b038082166060850152806080840151166080850152505060ff60a08201511660a083015260ff60c08201511660c08301525050565b60006101c082019050898252886020830152876040830152866060830152615a056080830187615974565b6001600160a01b03948516610160830152929093166101808401526001600160701b03166101a09092019190915295945050505050565b60208152600061228f60208301846157f7565b805180151581146142f657600080fd5b60008060408385031215615a7257600080fd5b615a7b83615a4f565b9150602083015190509250929050565b6000610160820190508682528560208301528460408301528360608301526156c86080830184615974565b600060808284031215615ac857600080fd5b604051608081016001600160401b0381118282101715615aea57615aea6142fb565b604052825160058110615afc57600080fd5b808252506020830151602082015260408301516040820152606083015160608201528091505092915050565b6020808252600490820152634533417360e01b604082015260600190565b6020808252600f908201526e125b98dbdc9c9958dd105b5bdd5b9d608a1b604082015260600190565b6000600160ff1b8201615b8457615b84615295565b5060000390565b60006001600160c01b038281168482168083038211156155c8576155c8615295565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600060208284031215615c0a57600080fd5b815161228f81614521565b600181815b80851115615c50578160001904821115615c3657615c36615295565b80851615615c4357918102915b93841c9390800290615c1a565b509250929050565b600082615c6757506001611ece565b81615c7457506000611ece565b8160018114615c8a5760028114615c9457615cb0565b6001915050611ece565b60ff841115615ca557615ca5615295565b50506001821b611ece565b5060208310610133831016604e8410600b8410161715615cd3575081810a611ece565b615cdd8383615c15565b8060001904821115615cf157615cf1615295565b029392505050565b600061228f8383615c58565b60006001600160ff1b0381841382841380821686840486111615615d2b57615d2b615295565b600160ff1b6000871282811687830589121615615d4a57615d4a615295565b60008712925087820587128484161615615d6657615d66615295565b87850587128184161615615d7c57615d7c615295565b505050929093029392505050565b60008083128015600160ff1b850184121615615da857615da8615295565b6001600160ff1b0384018313811615615dc357615dc3615295565b50500390565b600080821280156001600160ff1b0384900385131615615deb57615deb615295565b600160ff1b8390038412811615615e0457615e04615295565b50500190565b60208082526003908201526245313160e81b604082015260600190565b600060208284031215615e3957600080fd5b61228f82615a4f565b60006001600160c01b0383811690831681811015615e6257615e62615295565b039392505050565b8c81526001600160a01b038c811660208301528b811660408301528a811660608301528981166080830152881660a08201526001600160401b0387811660c083015286811660e083015285166101008201526101808101615ecf6101208301866142c9565b615edd6101408301856142c9565b60ff83166101608301529d9c50505050505050505050505050565b634e487b7160e01b600052603160045260246000fd5b60008251615f2081846020870161579f565b9190910192915050565b60208152600061228f60208301846157cb56fe2210a3e9136294756a7a989c32de6a75280c32dafeccc1280adcc9bb469f44a3565d6850cdd88f91fbcedecc61c18940ca739db2f1a27fc66ac9d4b236db81b8a26469706673582212202a3e234e5fdafae8c139081886d76210ecc5dd17e3d18f6f58b16b1039c5524764736f6c634300080f0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.