Polygon Sponsored slots available. Book your slot here!
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 46,416 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Pause | 63781804 | 172 days ago | IN | 0 POL | 0.0016256 | ||||
Start | 63781199 | 172 days ago | IN | 0 POL | 0.00674365 | ||||
Start | 63781191 | 172 days ago | IN | 0 POL | 0.00674365 | ||||
Start | 63781185 | 172 days ago | IN | 0 POL | 0.006744 | ||||
Start | 63781178 | 172 days ago | IN | 0 POL | 0.006744 | ||||
Start | 63781173 | 172 days ago | IN | 0 POL | 0.0067158 | ||||
Start | 63781166 | 172 days ago | IN | 0 POL | 0.00671615 | ||||
Start | 63781158 | 172 days ago | IN | 0 POL | 0.00671615 | ||||
Unpause | 63780545 | 172 days ago | IN | 0 POL | 0.00077991 | ||||
Start | 62649414 | 200 days ago | IN | 0.10667384 POL | 0.00339069 | ||||
Start | 62550065 | 202 days ago | IN | 0.10892314 POL | 0.00345538 | ||||
Start | 62537701 | 202 days ago | IN | 0.07961393 POL | 0.00316664 | ||||
Pause | 62462555 | 204 days ago | IN | 0 POL | 0.00141087 | ||||
Start | 62451367 | 205 days ago | IN | 0.08245556 POL | 0.01259028 | ||||
Start | 62451281 | 205 days ago | IN | 0.08242294 POL | 0.01258884 | ||||
Start | 62451276 | 205 days ago | IN | 0.08295344 POL | 0.0125892 | ||||
Start | 62451264 | 205 days ago | IN | 0.08245238 POL | 0.01258992 | ||||
Start | 62451186 | 205 days ago | IN | 0.08375669 POL | 0.01259028 | ||||
Start | 62451152 | 205 days ago | IN | 0.09225829 POL | 0.01259028 | ||||
Start | 62451109 | 205 days ago | IN | 0.08217814 POL | 0.01259028 | ||||
Start | 62451044 | 205 days ago | IN | 0.08169624 POL | 0.01258992 | ||||
Start | 62451041 | 205 days ago | IN | 0.08121248 POL | 0.01259028 | ||||
Start | 62451028 | 205 days ago | IN | 0.08139459 POL | 0.01259028 | ||||
Start | 62450988 | 205 days ago | IN | 0.08075081 POL | 0.01259028 | ||||
Start | 62450916 | 205 days ago | IN | 0.08217387 POL | 0.01263605 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
62451367 | 205 days ago | 0.08245556 POL | ||||
62451281 | 205 days ago | 0.08242294 POL | ||||
62451276 | 205 days ago | 0.08295344 POL | ||||
62451264 | 205 days ago | 0.08245238 POL | ||||
62451186 | 205 days ago | 0.08375669 POL | ||||
62451152 | 205 days ago | 0.09225829 POL | ||||
62451109 | 205 days ago | 0.08217814 POL | ||||
62451044 | 205 days ago | 0.08169624 POL | ||||
62451041 | 205 days ago | 0.08121248 POL | ||||
62451028 | 205 days ago | 0.08139459 POL | ||||
62450988 | 205 days ago | 0.08075081 POL | ||||
62450916 | 205 days ago | 0.08217387 POL | ||||
62450879 | 205 days ago | 0.0955827 POL | ||||
62450865 | 205 days ago | 0.08217581 POL | ||||
62450815 | 205 days ago | 0.08233668 POL | ||||
62450810 | 205 days ago | 0.08074042 POL | ||||
62450688 | 205 days ago | 0.080104 POL | ||||
62450637 | 205 days ago | 0.08010009 POL | ||||
62450576 | 205 days ago | 0.07988642 POL | ||||
62450574 | 205 days ago | 0.07989263 POL | ||||
62450564 | 205 days ago | 0.0810229 POL | ||||
62450557 | 205 days ago | 0.07989356 POL | ||||
62450464 | 205 days ago | 0.07984044 POL | ||||
62450452 | 205 days ago | 0.08338324 POL | ||||
62450387 | 205 days ago | 0.09138137 POL |
Loading...
Loading
Contract Name:
UnifiedRouterV2
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./RouterV2.sol"; import "./interfaces/IUnifiedPoolAdapter.sol"; contract UnifiedRouterV2 is RouterV2, IUnifiedRouter { event PoolAdapterSet(address pool, address poolAdapter); /// @dev add operation code bytes32 public constant ADD_CODE = keccak256(abi.encodePacked("A")); /// @dev remove operation code bytes32 public constant REMOVE_CODE = keccak256(abi.encodePacked("R")); /// @dev swap operation code bytes32 public constant SWAP_CODE = keccak256(abi.encodePacked("S")); /// @dev pool adapters mapping(address => address) public poolAdapter; constructor(address addressBook_) RouterV2(addressBook_) {} /** * @dev Sets pool adapter for given pool. * * Each supported pool must be set. * * @param pool_ The Curve pool; * @param poolAdapter_ The pool adapter for pool_. */ function setPoolAdapter( address pool_, address poolAdapter_ ) external onlyRole(OPERATOR_ROLE) { require(pool_ != address(0), "UnifiedRouterV2: zero address"); poolAdapter[pool_] = poolAdapter_; } /** * @dev Should be implemented for each router. * * Each implementation must: * Revert execution if op is not supported; * Return chainId, destination router (if current op is cross-chain) and execution result. * * @param op operation hash; * @param params serialized params corresponding to op. */ function _executeOp( bool isOpHalfDone, bytes32 op, bytes32 nextOp, bytes memory params, MaskedParams memory prevMaskedParams ) internal virtual override returns (uint64 chainIdTo, bytes memory updatedParams, MaskedParams memory maskedParams, ExecutionResult result) { (chainIdTo, updatedParams, maskedParams, result) = super._executeOp(isOpHalfDone, op, nextOp, params, prevMaskedParams); if (result == ExecutionResult.Failed) { result = ExecutionResult.Succeeded; if (ADD_CODE == op) { AddParams memory p = abi.decode(params, (AddParams)); address adapter = _getPoolAdapter(p.pool); (p.amountIn, p.from, p.emergencyTo) = _checkMaskedParams(p.amountIn, p.from, p.emergencyTo, maskedParams); p.to = _checkTo(p.to, p.emergencyTo, uint64(block.chainid), nextOp); _transferToAdapter(p.tokenIn, p.from, adapter, p.amountIn); maskedParams.amountOut = IUnifiedPoolAdapter(adapter).addLiquidity( p.tokenIn, p.amountIn, p.to, p.pool, p.minAmountOut, p.i, p.emergencyTo ); maskedParams.to = p.to; maskedParams.emergencyTo = p.emergencyTo; if (maskedParams.amountOut == 0) { if (isOriginNetwork) { revert("UnifiedRouterV2: slippage"); } result = ExecutionResult.Interrupted; } } else if (REMOVE_CODE == op) { RemoveParams memory p = abi.decode(params, (RemoveParams)); address adapter = _getPoolAdapter(p.pool); (p.amountIn, p.from, p.emergencyTo) = _checkMaskedParams(p.amountIn, p.from, p.emergencyTo, maskedParams); p.to = _checkTo(p.to, p.emergencyTo, uint64(block.chainid), nextOp); _transferToAdapter(p.tokenIn, p.from, adapter, p.amountIn); maskedParams.amountOut = IUnifiedPoolAdapter(adapter).removeLiquidity( p.tokenIn, p.amountIn, p.to, p.pool, p.minAmountOut, p.j, p.emergencyTo ); maskedParams.to = p.to; maskedParams.emergencyTo = p.emergencyTo; if (maskedParams.amountOut == 0) { if (isOriginNetwork) { revert("UnifiedRouterV2: slippage"); } result = ExecutionResult.Interrupted; } } else if (SWAP_CODE == op) { SwapParams memory p = abi.decode(params, (SwapParams)); address adapter = _getPoolAdapter(p.pool); (p.amountIn, p.from, p.emergencyTo) = _checkMaskedParams(p.amountIn, p.from, p.emergencyTo, maskedParams); p.to = _checkTo(p.to, p.emergencyTo, uint64(block.chainid), nextOp); _transferToAdapter(p.tokenIn, p.from, adapter, p.amountIn); maskedParams.amountOut = IUnifiedPoolAdapter(adapter).swap( p.tokenIn, p.amountIn, p.to, p.pool, p.minAmountOut, p.i, p.j, p.emergencyTo ); maskedParams.to = p.to; maskedParams.emergencyTo = p.emergencyTo; if (maskedParams.amountOut == 0) { if (isOriginNetwork) { revert("UnifiedRouterV2: slippage"); } result = ExecutionResult.Interrupted; } } else { result = ExecutionResult.Failed; } } } function _checkTo(address to, address emergencyTo, uint64 chainId, bytes32 nextOp) internal view virtual override returns (address correctTo) { correctTo = super._checkTo(to, emergencyTo, chainId, nextOp); if (correctTo == address(0)) { if (nextOp == ADD_CODE || nextOp == REMOVE_CODE || nextOp == SWAP_CODE) { correctTo = IAddressBook(addressBook).router(chainId); } } } function _getPoolAdapter(address pool) private view returns (address adapter) { adapter = poolAdapter[pool]; require(adapter != address(0), "UnifiedRouterV2: pool adapter not set"); } function _transferToAdapter(address tokenIn, address from, address adapter, uint256 amountIn) private { if (from == address(this)) { SafeERC20.safeTransfer(IERC20(tokenIn), adapter, amountIn); } else { SafeERC20.safeTransferFrom(IERC20(tokenIn), from, adapter, amountIn); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(account), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControlEnumerable.sol"; import "./AccessControl.sol"; import "../utils/structs/EnumerableSet.sol"; /** * @dev Extension of {AccessControl} that allows enumerating the members of each role. */ abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { using EnumerableSet for EnumerableSet.AddressSet; mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) { return _roleMembers[role].at(index); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) { return _roleMembers[role].length(); } /** * @dev Overload {_grantRole} to track enumerable memberships */ function _grantRole(bytes32 role, address account) internal virtual override { super._grantRole(role, account); _roleMembers[role].add(account); } /** * @dev Overload {_revokeRole} to track enumerable memberships */ function _revokeRole(bytes32 role, address account) internal virtual override { super._revokeRole(role, account); _roleMembers[role].remove(account); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. */ interface IAccessControlEnumerable is IAccessControl { /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) external view returns (address); /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.0; interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// 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.3) (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. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ 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 v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library Counters { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// 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/cryptography/EIP712.sol) pragma solidity ^0.8.8; import "./ECDSA.sol"; import "../ShortStrings.sol"; import "../../interfaces/IERC5267.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * _Available since v3.4._ * * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment */ abstract contract EIP712 is IERC5267 { using ShortStrings for *; bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; address private immutable _cachedThis; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _name = name.toShortStringWithFallback(_nameFallback); _version = version.toShortStringWithFallback(_versionFallback); _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _cachedThis && block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {EIP-5267}. * * _Available since v4.9._ */ function eip712Domain() public view virtual override returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return ( hex"0f", // 01111 _name.toStringWithFallback(_nameFallback), _version.toStringWithFallback(_versionFallback), block.chainid, address(this), bytes32(0), new uint256[](0) ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// 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.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/ShortStrings.sol) pragma solidity ^0.8.8; import "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); /// @solidity memory-safe-assembly assembly { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(_FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// 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: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; import "./EndPoint.sol"; import "./interfaces/IGateKeeper.sol"; import "./interfaces/IRouterV2.sol"; import "./interfaces/IAddressBook.sol"; import "./utils/RequestIdLib.sol"; abstract contract BaseRouter is Pausable, EIP712, EndPoint, AccessControlEnumerable { using Counters for Counters.Counter; enum ExecutionResult { Failed, Succeeded, Interrupted } struct ComplexOp { string operation; bool registered; } struct MaskedParams { uint256 amountOut; address to; address emergencyTo; } /// @dev accountant role id bytes32 public constant ACCOUNTANT_ROLE = keccak256("ACCOUNTANT_ROLE"); /// @dev operator role id bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); /// @dev registered operations mapping(bytes32 => bool) public ops; /// @dev nonces mapping(address => Counters.Counter) private _nonces; /// @dev started crocss-chain ops, requestId => serialized op params mapping(bytes32 => bytes) public startedOps; /// @dev used to check is function called from resume\onlyBridge handler, otherwise not set bytes32 internal currentRequestId; /// @dev should be set between receiveValidatedData and resume call uint64 internal currentChainIdFrom; /// @dev should be true when start proceeding (only on initial call) bool internal isOriginNetwork; event FeePaid(address indexed payer, address accountant, uint256 executionPrice); event ComplexOpProcessed( uint64 currentChainId, bytes32 currentRequestId, uint64 nextChainId, bytes32 nextRequestId, ExecutionResult result, uint8 lastOp ); event ComplexOpSet(string oop, bytes32 hash, bool registered); modifier originNetwork() { isOriginNetwork = true; _; isOriginNetwork = false; } modifier crosschainHandling(bytes32 requestId) { currentRequestId = requestId; _; currentRequestId = 0; currentChainIdFrom = 0; } constructor( address addressBook_ ) EIP712("EYWA", "1") EndPoint(addressBook_) { _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); } function nonces(address whose) public view returns (uint256) { return _nonces[whose].current(); } /** * @dev Registers set of complex operation. * * @param complexOps_ array of complex operations and registered flags. */ function registerComplexOp(ComplexOp[] memory complexOps_) external onlyRole(OPERATOR_ROLE) { uint256 length = complexOps_.length; for (uint256 i; i < length; ++i) { bytes32 oop = keccak256(bytes(complexOps_[i].operation)); ops[oop] = complexOps_[i].registered; emit ComplexOpSet(complexOps_[i].operation, oop, complexOps_[i].registered); } } /** * @dev Sets address book. * * Controlled by DAO and\or multisig (3 out of 5, Gnosis Safe). * * @param addressBook_ address book contract address. */ function setAddressBook(address addressBook_) external onlyRole(DEFAULT_ADMIN_ROLE) { _setAddressBook(addressBook_); } /** * @dev Triggers stopped state. * * Controlled by DAO and\or multisig (3 out of 5, Gnosis Safe). */ function pause() external onlyRole(DEFAULT_ADMIN_ROLE) { _pause(); } /** * @dev Returns to normal state. * * Controlled by DAO and\or multisig (3 out of 5, Gnosis Safe). */ function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) { _unpause(); } /** * @dev Token synthesize request to another EVM chain via native payment. * * A: Lock(X) -> B: Mint(sX_A) = sX_A * * @param operations operation types; * @param params operation params; * @param receipt clp invoice. */ function _start( string[] calldata operations, bytes[] memory params, IRouterParams.Invoice calldata receipt ) internal virtual { require(operations.length < 2**8, "BaseRouter: wrong params count"); require(operations.length == params.length, "BaseRouter: wrong params"); { (bytes32 hash, bytes memory data) = _getRawData(operations, params); require(ops[hash] == true, "BaseRouter: complex op not registered"); address accountant = _checkSignature(msg.sender, hash, data, receipt); _proceedFees(receipt.executionPrice, accountant); } ( bytes32 nextRequestId, uint64 chainIdTo, ExecutionResult result, uint8 lastOp ) = _execute(0, operations, params); emit ComplexOpProcessed(uint64(block.chainid), 0, chainIdTo, nextRequestId, result, lastOp); } function _resume( bytes32 requestId, uint8 cPos, string[] calldata operations, bytes[] memory params ) internal virtual { require(operations.length < 2**8, "BaseRouter: wrong params count"); require(operations.length == params.length, "BaseRouter: wrong params"); require(cPos < params.length, "BaseRouter: wrong params"); ( bytes32 nextRequestId, uint64 chainIdTo, ExecutionResult result, uint8 lastOp ) = _execute(cPos, operations, params); emit ComplexOpProcessed(uint64(block.chainid), requestId, chainIdTo, nextRequestId, result, lastOp); } function _execute(uint256 cPos, string[] calldata operations, bytes[] memory params) internal virtual whenNotPaused returns ( bytes32 nextRequestId, uint64 chainIdTo, ExecutionResult result, uint8 lastOp ) { MaskedParams memory maskedParams; bytes memory updatedParams; for (uint256 i = cPos; i < operations.length; ++i) { (chainIdTo, updatedParams, maskedParams, result) = _executeOp( (currentRequestId != 0 && i == cPos), keccak256(bytes(operations[i])), i < (operations.length - 1) ? keccak256(bytes(operations[i + 1])) : bytes32(0), params[i], maskedParams ); require(result != ExecutionResult.Failed, string(abi.encodePacked("Router: op ", operations[i], " is not supported"))); lastOp = uint8(i); if (result == ExecutionResult.Interrupted) { break; } else if (chainIdTo != 0) { address router = IAddressBook(addressBook).router(chainIdTo); nextRequestId = _getRequestId(router, chainIdTo); if (updatedParams.length != 0) { params[i] = updatedParams; } bytes memory out = abi.encodeWithSelector( IRouter.resume.selector, nextRequestId, uint8(i), operations, params ); address gateKeeper = IAddressBook(addressBook).gateKeeper(); IGateKeeper(gateKeeper).sendData(out, router, chainIdTo, address(0)); startedOps[nextRequestId] = params[i]; break; } } } /** * @dev Returns current nonce and increment it. * * @param whose whose nonce. */ function _getAndUpdateNonce(address whose) internal returns (uint256 nonce) { Counters.Counter storage counter = _nonces[whose]; nonce = counter.current(); counter.increment(); } function _checkSignature( address from, bytes32 operationHash, bytes memory data, IRouterParams.Invoice calldata receipt ) internal returns (address accountant) { uint256 nonce = _getAndUpdateNonce(from); bytes32 accountantHash = keccak256( abi.encodePacked( keccak256( "AccountantPermit(address from,uint256 nonce,bytes32 operationHash,bytes data,uint256 executionPrice,uint256 deadline)" ), from, nonce, operationHash, data, receipt.executionPrice, receipt.deadline ) ); bytes32 hash = ECDSA.toEthSignedMessageHash(_hashTypedDataV4(accountantHash)); accountant = ECDSA.recover(hash, receipt.v, receipt.r, receipt.s); require(block.timestamp <= receipt.deadline, "BaseRouter: deadline"); require(hasRole(ACCOUNTANT_ROLE, accountant), "BaseRouter: invalid signature from worker"); } function _getRawData( string[] calldata operations, bytes[] memory params ) internal pure returns (bytes32 hash, bytes memory data) { bytes memory op; for (uint256 i = 0; i < operations.length; ++i) { op = bytes.concat(op, bytes(operations[i])); data = bytes.concat(data, params[i]); } hash = keccak256(op); } function _getRequestId(address receiver, uint64 chainIdTo) internal view returns (bytes32 requestId) { address gateKeeper = IAddressBook(addressBook).gateKeeper(); uint256 nonce = IGateKeeper(gateKeeper).getNonce(); requestId = RequestIdLib.prepareRequestId( castToBytes32(receiver), chainIdTo, castToBytes32(address(this)), block.chainid, nonce ); } function _proceedFees(uint256 executionPrice, address accountant) internal virtual; function _executeOp( bool isOpHalfDone, bytes32 op, bytes32 nextOp, bytes memory params, MaskedParams memory prevMaskedParams ) internal virtual returns ( uint64 chainIdTo, bytes memory updatedParams, MaskedParams memory maskedParams, ExecutionResult result ); }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; import "./utils/Typecast.sol"; contract EndPoint is Typecast { /// @dev version string public version; /// @dev clp address book address public addressBook; constructor (address addressBook_) { version = "2.2.3"; _checkAddress(addressBook_); addressBook = addressBook_; } function _setAddressBook(address addressBook_) internal { _checkAddress(addressBook_); addressBook = addressBook_; } function _checkAddress(address checkingAddress) private pure { require(checkingAddress != address(0), "EndPoint: zero address"); } }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; interface IAddressBook { /// @dev returns portal by given chainId function portal(uint64 chainId) external view returns (address); /// @dev returns synthesis by given chainId function synthesis(uint64 chainId) external view returns (address); /// @dev returns router by given chainId function router(uint64 chainId) external view returns (address); /// @dev returns whitelist function whitelist() external view returns (address); /// @dev returns treasury function treasury() external view returns (address); /// @dev returns gateKeeper function gateKeeper() external view returns (address); /// @dev returns bridge function bridge() external view returns (address); }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; interface IERC20WithPermit { function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; interface IGateKeeper { function calculateCost( address payToken, uint256 dataLength, uint64 chainIdTo, address sender ) external returns (uint256 amountToPay); function sendData( bytes calldata data, address to, uint64 chainIdTo, address payToken ) external payable; function getNonce() external view returns (uint256); function bridge() external view returns (address); }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; interface IPortalV2 { function lock( address token, uint256 amount, address from, address to ) external; function unlock( address token, uint256 amount, address from, address to ) external returns (uint256); function emergencyUnlock( address token, uint256 amount, address from, address to ) external returns (uint256); }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; interface IRouterParams { struct Invoice { uint256 executionPrice; uint256 deadline; uint8 v; bytes32 r; bytes32 s; } struct PermitParams { address token; address owner; uint256 amount; uint256 deadline; uint8 v; bytes32 r; bytes32 s; } /** * @dev amount can be set as prev op result by using uint256 max. */ struct SynthParams { address tokenIn; uint256 amountIn; // amount | 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff address from; // from | 0x0000000000000000000000000000000000000000 address to; uint64 chainIdTo; uint64 tokenInChainIdFrom; address emergencyTo; } /** * @dev Cancellation applicable only for cross-chain ops (LM, BU, BM). */ struct CancelParams { bytes32 requestId; uint64 chainIdTo; } /** * @dev amountIn can be set as prev op result by using uint256 max. */ struct AddParams { address tokenIn; uint256 amountIn; // amount | 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff address from; // from | 0x0000000000000000000000000000000000000000 address to; address pool; uint256 minAmountOut; uint8 i; address emergencyTo; } /** * @dev amountIn can be set as prev op result by using uint256 max. */ struct RemoveParams { address tokenIn; uint256 amountIn; // amount | 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff address from; // from | 0x0000000000000000000000000000000000000000 address to; address pool; uint256 minAmountOut; uint8 j; address emergencyTo; } /** * @dev amountIn can be set as prev op result by using uint256 max. */ struct SwapParams { address tokenIn; uint256 amountIn; // amount | 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff address from; // from | 0x0000000000000000000000000000000000000000 address to; address pool; uint256 minAmountOut; uint8 i; uint8 j; address emergencyTo; } /** * @dev amount can be set as prev op result by using uint256 max. */ struct WrapParams { address tokenIn; uint256 amountIn; // amount | 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff address from; // from | 0x0000000000000000000000000000000000000000 address to; // router if op not last } } interface IRouter is IRouterParams { function start( string[] calldata operations, bytes[] calldata params, Invoice calldata receipt ) external payable; function resume( bytes32 requestId, uint8 cPos, string[] calldata operations, bytes[] calldata params ) external; } interface IUnifiedRouter is IRouter { }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @dev Should be implemented by "treasury" contract in cases when third party token used instead of our synth. * * Mint\Burn can be implemented as Lock\Unlock in treasury contract. */ interface ISynthAdapter { enum SynthType { Unknown, DefaultSynth, CustomSynth, ThirdPartySynth, ThirdPartyToken } function mint(address account, uint256 amount) external; function burn(address account, uint256 amount) external; function setCap(uint256) external; function decimals() external view returns (uint8); function originalToken() external view returns (address); function synthToken() external view returns (address); function chainIdFrom() external view returns (uint64); // TODO what if token native in 2-3-4 chains? // [] function chainSymbolFrom() external view returns (string memory); function synthType() external view returns (uint8); function cap() external view returns (uint256); event CapSet(uint256 cap); } interface ISynthERC20 is ISynthAdapter, IERC20 { function mintWithAllowanceIncrease(address account, address spender, uint256 amount) external; function burnWithAllowanceDecrease(address account, address spender, uint256 amount) external; }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; interface ISynthesisV2 { function synthByOriginal(uint64 chainIdFrom, address otoken) external view returns (address stoken); function synthBySynth(address stoken) external view returns (address adapter); function mint( address token, uint256 amount, address from, address to, uint64 chainIdFrom ) external returns (uint256 amountOut); function emergencyMint( address token, uint256 amount, address from, address to ) external returns (uint256 amountOut); function burn( address stoken, uint256 amount, address from, address to, uint64 chainIdTo ) external; }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; interface IUnifiedPoolAdapter { function addLiquidity( address tokenIn, uint256 amountIn, address to, address pool, uint256 minAmountOut, uint8 i, address emergencyTo ) external returns (uint256 amountOut); function swap( address tokenIn, uint256 amountIn, address to, address pool, uint256 minAmountOut, uint8 i, uint8 j, address emergencyTo ) external returns (uint256 amountOut); function removeLiquidity( address tokenIn, uint256 amountIn, address to, address pool, uint256 minAmountOut, uint8 j, address emergencyTo ) external returns (uint256 amountOut); }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; interface IWETH9 { function withdraw(uint wad) external; function deposit() external payable; }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "./BaseRouter.sol"; import "./interfaces/IPortalV2.sol"; import "./interfaces/ISynthesisV2.sol"; import "./interfaces/IRouterV2.sol"; import "./interfaces/IAddressBook.sol"; import "./interfaces/IWETH.sol"; import "./interfaces/IERC20WithPermit.sol"; import "./interfaces/ISynth.sol"; contract RouterV2 is BaseRouter, ReentrancyGuard, IRouter { enum CrossChainOpState { Unknown, Succeeded, Reverted } /// @dev permit operation code bytes32 public constant PERMIT_CODE = keccak256(abi.encodePacked("P")); /// @dev lock operation code bytes32 public constant LOCK_MINT_CODE = keccak256(abi.encodePacked("LM")); /// @dev unlock operation code bytes32 public constant BURN_UNLOCK_CODE = keccak256(abi.encodePacked("BU")); /// @dev mint operation code bytes32 public constant BURN_MINT_CODE = keccak256(abi.encodePacked("BM")); /// @dev wrap operation code bytes32 public constant WRAP_CODE = keccak256(abi.encodePacked("W")); /// @dev unwrap operation code bytes32 public constant UNWRAP_CODE = keccak256(abi.encodePacked("Uw")); /// @dev emergency cancel lock operation code bytes32 public constant EMERGENCY_UNLOCK_CODE = keccak256(abi.encodePacked("!M")); /// @dev emergency cancel burn operation code bytes32 public constant EMERGENCY_MINT_CODE = keccak256(abi.encodePacked("!U")); /// @dev processed cross-chain ops (can't be reverted) mapping(bytes32 => CrossChainOpState) public processedOps; modifier onlyBridge() { address bridge = IAddressBook(addressBook).bridge(); require(bridge == msg.sender, "Router: bridge only"); _; } constructor(address addressBook_) BaseRouter(addressBook_) {} receive() external payable {} function receiveValidatedData(bytes4 selector, address from, uint64 chainIdFrom) external virtual onlyBridge returns (bool) { address router = IAddressBook(addressBook).router(chainIdFrom); require(from == router, "Router: wrong sender"); require(selector == RouterV2.resume.selector, "Router: wrong selector"); currentChainIdFrom = chainIdFrom; return true; } /** * @dev Token synthesize request to another EVM chain via native payment. * * A: Lock(X) -> B: Mint(sX_A) = sX_A * * @param operations operation types; * @param params operation params; * @param receipt clp invoice. */ function start( string[] calldata operations, bytes[] memory params, Invoice calldata receipt ) external payable originNetwork nonReentrant { _start(operations, params, receipt); } function resume( bytes32 requestId, uint8 cPos, string[] calldata operations, bytes[] memory params ) external onlyBridge crosschainHandling(requestId) nonReentrant { _resume(requestId, cPos, operations, params); } /** * @dev Should be implemented for each router. * * Each implementation must: * Revert execution if op is not supported; * Return chainId and destination router if current op is cross-chain; */ function _executeOp( bool isOpHalfDone, bytes32 op, bytes32 nextOp, bytes memory params, MaskedParams memory prevMaskedParams ) internal virtual override returns (uint64 chainIdTo, bytes memory updatedParams, MaskedParams memory maskedParams, ExecutionResult result) { result = ExecutionResult.Succeeded; if (PERMIT_CODE == op) { PermitParams memory p = abi.decode(params, (PermitParams)); IERC20WithPermit(p.token).permit( p.owner, address(this), p.amount, p.deadline, p.v, p.r, p.s ); } else if (LOCK_MINT_CODE == op || BURN_UNLOCK_CODE == op || BURN_MINT_CODE == op) { SynthParams memory p = abi.decode(params, (SynthParams)); if (isOpHalfDone == false) { (p.amountIn, p.from, p.emergencyTo) = _checkMaskedParams(p.amountIn, p.from, p.emergencyTo, prevMaskedParams); p.to = _checkTo(p.to, p.emergencyTo, p.chainIdTo, nextOp); address possibleAdapter; if (LOCK_MINT_CODE == op) { _lock(p); } else { address synthesis = IAddressBook(addressBook).synthesis(uint64(block.chainid)); possibleAdapter = ISynthesisV2(synthesis).synthBySynth(p.tokenIn); if (possibleAdapter != address(0)) { if (p.from != synthesis) { SafeERC20.safeTransferFrom(IERC20(p.tokenIn), p.from, synthesis, p.amountIn); } p.from = synthesis; } else { possibleAdapter = p.tokenIn; } ISynthesisV2(synthesis).burn(p.tokenIn, p.amountIn, p.from, p.to, p.chainIdTo); } chainIdTo = p.chainIdTo; if (LOCK_MINT_CODE != op) { ISynthAdapter synthImpl = ISynthAdapter(possibleAdapter); p.tokenIn = synthImpl.originalToken(); p.tokenInChainIdFrom = synthImpl.chainIdFrom(); } else { p.tokenInChainIdFrom = uint64(block.chainid); } updatedParams = abi.encode(p); } else { require(processedOps[currentRequestId] == CrossChainOpState.Unknown, "Router: op processed"); processedOps[currentRequestId] = CrossChainOpState.Succeeded; if (p.to == address(0)) { p.to = _checkTo(p.to, p.emergencyTo, p.chainIdTo, nextOp); } maskedParams.amountOut = BURN_UNLOCK_CODE == op ? _unlock(p) : _mint(p); maskedParams.to = p.to; maskedParams.emergencyTo = p.emergencyTo; } } else if (WRAP_CODE == op || UNWRAP_CODE == op) { WrapParams memory p = abi.decode(params, (WrapParams)); address tmp; (p.amountIn, p.from, tmp) = _checkMaskedParams(p.amountIn, p.from, address(0), prevMaskedParams); p.to = _checkTo(p.to, p.to, uint64(block.chainid), nextOp); maskedParams.amountOut = WRAP_CODE == op ? _wrap(p) : _unwrap(p); maskedParams.to = p.to; maskedParams.emergencyTo = prevMaskedParams.emergencyTo; } else if (EMERGENCY_UNLOCK_CODE == op || EMERGENCY_MINT_CODE == op) { CancelParams memory p = abi.decode(params, (CancelParams)); if (isOpHalfDone == false) { require(processedOps[p.requestId] != CrossChainOpState.Succeeded, "Router: op processed"); processedOps[p.requestId] = CrossChainOpState.Reverted; chainIdTo = p.chainIdTo; } else { bytes memory emergencyParams = startedOps[p.requestId]; require(emergencyParams.length != 0, "Router: op not started"); SynthParams memory eP = abi.decode(emergencyParams, (SynthParams)); delete startedOps[p.requestId]; if (EMERGENCY_UNLOCK_CODE == op) { maskedParams.amountOut = _emergencyUnlock(eP); } else { maskedParams.amountOut = _emergencyMint(eP); } } } else { maskedParams = prevMaskedParams; result = ExecutionResult.Failed; } } function _lock(SynthParams memory p) internal { address portal = IAddressBook(addressBook).portal(uint64(block.chainid)); if (p.from != portal) { SafeERC20.safeTransferFrom(IERC20(p.tokenIn), p.from, portal, p.amountIn); } IPortalV2(portal).lock(p.tokenIn, p.amountIn, p.from, p.to); } function _unlock(SynthParams memory p) internal returns (uint256 amountOut) { address portal = IAddressBook(addressBook).portal(uint64(block.chainid)); amountOut = IPortalV2(portal).unlock(p.tokenIn, p.amountIn, p.from, p.to); } function _emergencyUnlock(SynthParams memory p) internal returns (uint256 amountOut) { require(currentChainIdFrom == p.chainIdTo, "Router: wrong emergency init"); address portal = IAddressBook(addressBook).portal(uint64(block.chainid)); amountOut = IPortalV2(portal).emergencyUnlock(p.tokenIn, p.amountIn, p.from, p.emergencyTo); } function _mint(SynthParams memory p) internal returns (uint256 amountOut) { address synthesis = IAddressBook(addressBook).synthesis(uint64(block.chainid)); amountOut = ISynthesisV2(synthesis).mint(p.tokenIn, p.amountIn, p.from, p.to, p.tokenInChainIdFrom); } function _emergencyMint(SynthParams memory p) internal returns (uint256 amountOut) { require(currentChainIdFrom == p.chainIdTo, "Router: wrong emergency init"); address synthesis = IAddressBook(addressBook).synthesis(uint64(block.chainid)); p.tokenIn = ISynthesisV2(synthesis).synthByOriginal(p.tokenInChainIdFrom, p.tokenIn); amountOut = ISynthesisV2(synthesis).emergencyMint(p.tokenIn, p.amountIn, p.from, p.emergencyTo); } function _wrap(WrapParams memory p) internal returns (uint256 amountOut) { require(msg.value >= p.amountIn, "Router: invalid amount"); IWETH9(p.tokenIn).deposit{ value: p.amountIn }(); SafeERC20.safeTransfer(IERC20(p.tokenIn), p.to, p.amountIn); amountOut = p.amountIn; } function _unwrap(WrapParams memory p) internal returns (uint256 amountOut) { if (p.from != address(this)) { SafeERC20.safeTransferFrom(IERC20(p.tokenIn), p.from, address(this), p.amountIn); } IWETH9(p.tokenIn).withdraw(p.amountIn); (bool sent, ) = p.to.call{ value: p.amountIn }(""); require(sent, "Router: failed to send ETH"); amountOut = p.amountIn; } function _proceedFees(uint256 executionPrice, address accountant) internal virtual override { require(msg.value >= executionPrice, "Router: invalid amount"); (bool sent, ) = accountant.call{ value: executionPrice }(""); require(sent, "Router: failed to send Ether"); emit FeePaid(msg.sender, accountant, executionPrice); } /** * @dev Should check current params for mask and return correct values. * * @param currentAmountIn current op amountIn, can be UINT256_MAX; * @param currentFrom current op from, always must be equal address(0), except initial op; * @param currentEmergencyTo current op emergencyTo, must be msg.sender in initial op or addres(0) in all others; * @param prevMaskedParams prev params, which can be used to update current given params. */ function _checkMaskedParams( uint256 currentAmountIn, address currentFrom, address currentEmergencyTo, MaskedParams memory prevMaskedParams ) internal view returns (uint256 amountIn, address from, address emergencyTo) { // amountIn check amountIn = currentAmountIn == type(uint256).max ? prevMaskedParams.amountOut : currentAmountIn; // from check if (currentFrom != address(0)) { require(currentFrom == msg.sender, "Router: wrong sender"); from = currentFrom; } else { from = prevMaskedParams.to; } // emergencyTo check if (currentRequestId == 0 && currentEmergencyTo != address(0)) { // only in initial chain (currentRequestId always 0) require(currentEmergencyTo == msg.sender, "Router: wrong emergencyTo"); emergencyTo = currentEmergencyTo; } else { // on next chain always using first one emergencyTo = prevMaskedParams.emergencyTo; } } function _checkTo(address to, address emergencyTo, uint64 chainId, bytes32 nextOp) internal view virtual returns (address correctTo) { require(to == address(0) || nextOp == bytes32(0), "Router: wrong to"); if (nextOp == bytes32(0)) { correctTo = to; require(correctTo == emergencyTo, "Router: wrong receiver"); } else if (nextOp == LOCK_MINT_CODE) { correctTo = IAddressBook(addressBook).portal(chainId); } else if (nextOp == BURN_UNLOCK_CODE || nextOp == BURN_MINT_CODE) { correctTo = IAddressBook(addressBook).synthesis(chainId); } else if (WRAP_CODE == nextOp || UNWRAP_CODE == nextOp) { correctTo = IAddressBook(addressBook).router(chainId); } } }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; library RequestIdLib { /** * @dev Prepares a request ID with the given arguments. * * @param to receiver; * @param chainIdTo opposite chain id; * @param from sender; * @param chainIdFrom current chain id; * @param nonce current nonce. */ function prepareRequestId( bytes32 to, uint256 chainIdTo, bytes32 from, uint256 chainIdFrom, uint256 nonce ) internal pure returns (bytes32) { return keccak256(abi.encodePacked(from, nonce, chainIdTo, chainIdFrom, to)); } }
// SPDX-License-Identifier: UNLICENSED // Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved pragma solidity 0.8.17; abstract contract Typecast { function castToAddress(bytes32 x) public pure returns (address) { return address(uint160(uint256(x))); } function castToBytes32(address a) public pure returns (bytes32) { return bytes32(uint256(uint160(a))); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"addressBook_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"currentChainId","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"currentRequestId","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"nextChainId","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"nextRequestId","type":"bytes32"},{"indexed":false,"internalType":"enum BaseRouter.ExecutionResult","name":"result","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"lastOp","type":"uint8"}],"name":"ComplexOpProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"oop","type":"string"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"registered","type":"bool"}],"name":"ComplexOpSet","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"address","name":"accountant","type":"address"},{"indexed":false,"internalType":"uint256","name":"executionPrice","type":"uint256"}],"name":"FeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"address","name":"poolAdapter","type":"address"}],"name":"PoolAdapterSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"ACCOUNTANT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ADD_CODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BURN_MINT_CODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BURN_UNLOCK_CODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMERGENCY_MINT_CODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMERGENCY_UNLOCK_CODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOCK_MINT_CODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_CODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REMOVE_CODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SWAP_CODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNWRAP_CODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WRAP_CODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"addressBook","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"x","type":"bytes32"}],"name":"castToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"castToBytes32","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"whose","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"ops","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"poolAdapter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"processedOps","outputs":[{"internalType":"enum RouterV2.CrossChainOpState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint64","name":"chainIdFrom","type":"uint64"}],"name":"receiveValidatedData","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"operation","type":"string"},{"internalType":"bool","name":"registered","type":"bool"}],"internalType":"struct BaseRouter.ComplexOp[]","name":"complexOps_","type":"tuple[]"}],"name":"registerComplexOp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"uint8","name":"cPos","type":"uint8"},{"internalType":"string[]","name":"operations","type":"string[]"},{"internalType":"bytes[]","name":"params","type":"bytes[]"}],"name":"resume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addressBook_","type":"address"}],"name":"setAddressBook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool_","type":"address"},{"internalType":"address","name":"poolAdapter_","type":"address"}],"name":"setPoolAdapter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"operations","type":"string[]"},{"internalType":"bytes[]","name":"params","type":"bytes[]"},{"components":[{"internalType":"uint256","name":"executionPrice","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IRouterParams.Invoice","name":"receipt","type":"tuple"}],"name":"start","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"startedOps","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101606040523480156200001257600080fd5b506040516200611738038062006117833981016040819052620000359162000405565b60408051808201825260048152634559574160e01b60208083019190915282518084019093526001808452603160f81b848301526000805460ff1916905584938493849390926200009291849190620010c3620001b8821b17901c565b61012052620000af816002620001b8602090811b620010c317901c565b61014052815160208084019190912060e052815190820120610100524660a0526200013d60e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052604080518082019091526005815264322e322e3360d81b6020820152600390620001719082620004d4565b506200017d8162000208565b600480546001600160a01b0319166001600160a01b0392909216919091179055620001aa60003362000267565b50506001600c555062000615565b6000602083511015620001d857620001d083620002aa565b905062000202565b82620001ef83620002ed60201b620002c81760201c565b90620001fc9082620004d4565b5060ff90505b92915050565b6001600160a01b038116620002645760405162461bcd60e51b815260206004820152601660248201527f456e64506f696e743a207a65726f20616464726573730000000000000000000060448201526064015b60405180910390fd5b50565b6200027e8282620002f060201b620010f41760201c565b6000828152600660209081526040909120620002a59183906200117a62000395821b17901c565b505050565b600080829050601f81511115620002d8578260405163305a27a960e01b81526004016200025b9190620005a0565b8051620002e582620005f0565b179392505050565b90565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff16620003915760008281526005602090815260408083206001600160a01b03851684529091529020805460ff19166001179055620003503390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000620003ac836001600160a01b038416620003b3565b9392505050565b6000818152600183016020526040812054620003fc5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000202565b50600062000202565b6000602082840312156200041857600080fd5b81516001600160a01b0381168114620003ac57600080fd5b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200045b57607f821691505b6020821081036200047c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002a557600081815260208120601f850160051c81016020861015620004ab5750805b601f850160051c820191505b81811015620004cc57828155600101620004b7565b505050505050565b81516001600160401b03811115620004f057620004f062000430565b620005088162000501845462000446565b8462000482565b602080601f831160018114620005405760008415620005275750858301515b600019600386901b1c1916600185901b178555620004cc565b600085815260208120601f198616915b82811015620005715788860151825594840194600190910190840162000550565b5085821015620005905787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208083528351808285015260005b81811015620005cf57858101830151858201604001528201620005b1565b506000604082860101526040601f19601f8301168501019250505092915050565b805160208083015191908110156200047c5760001960209190910360031b1b16919050565b60805160a05160c05160e051610100516101205161014051615aa7620006706000396000610b4201526000610b1701526000613914015260006138ec01526000613847015260006138710152600061389b0152615aa76000f3fe60806040526004361061024a5760003560e01c80638456cb5911610139578063ad351f9f116100b6578063beadbe321161007a578063beadbe32146106a8578063ca15c873146106bd578063d547741f146106dd578063f5887cdd146106fd578063f5b541a61461071d578063f87cf42b1461075157600080fd5b8063ad351f9f14610620578063b2e1df7214610635578063b4ccca0d14610655578063ba677db714610675578063bcf4f0a61461068857600080fd5b80639ba520ad116100fd5780639ba520ad1461058d5780639bb68c75146105a2578063a217fddf146105b7578063a785ac5a146105cc578063ab1efbab146105ec57600080fd5b80638456cb59146104da57806384b0196e146104ef5780639010d07c1461051757806391d148541461053757806395ad709a1461055757600080fd5b80633e7e25c1116101c7578063692a34f41161018b578063692a34f4146104405780636b750d631461047057806376a3fb3e14610490578063778c89b9146104a55780637ecebe00146104ba57600080fd5b80633e7e25c1146103b55780633f4ba83a146103dc57806354fd4d50146103f15780635c975abb146104135780636869cb961461042b57600080fd5b80632b385bcf1161020e5780632b385bcf146103365780632d07ae691461034b5780632ee63e44146103605780632f2ff15d1461037557806336568abe1461039557600080fd5b806301ffc9a7146102565780630b3448a81461028b5780630e03e490146102ad5780630ff53ba7146102e3578063248a9ca31461030657600080fd5b3661025157005b600080fd5b34801561026257600080fd5b506102766102713660046148d8565b61078e565b60405190151581526020015b60405180910390f35b34801561029757600080fd5b506102ab6102a6366004614908565b6107b9565b005b3480156102b957600080fd5b506102cb6102c8366004614925565b90565b6040516001600160a01b039091168152602001610282565b3480156102ef57600080fd5b506102f86107d1565b604051908152602001610282565b34801561031257600080fd5b506102f8610321366004614925565b60009081526005602052604090206001015490565b34801561034257600080fd5b506102f86107fc565b34801561035757600080fd5b506102f8610811565b34801561036c57600080fd5b506102f8610826565b34801561038157600080fd5b506102ab61039036600461493e565b61083c565b3480156103a157600080fd5b506102ab6103b036600461493e565b610866565b3480156103c157600080fd5b506102f86103d0366004614908565b6001600160a01b031690565b3480156103e857600080fd5b506102ab6108e5565b3480156103fd57600080fd5b506104066108fb565b60405161028291906149be565b34801561041f57600080fd5b5060005460ff16610276565b34801561043757600080fd5b506102f8610989565b34801561044c57600080fd5b5061027661045b366004614925565b60076020526000908152604090205460ff1681565b34801561047c57600080fd5b506102ab61048b366004614bfc565b61099f565b34801561049c57600080fd5b506102f8610aac565b3480156104b157600080fd5b506102f8610ac2565b3480156104c657600080fd5b506102f86104d5366004614908565b610ad8565b3480156104e657600080fd5b506102ab610af6565b3480156104fb57600080fd5b50610504610b09565b6040516102829796959493929190614c81565b34801561052357600080fd5b506102cb610532366004614d17565b610b92565b34801561054357600080fd5b5061027661055236600461493e565b610bb1565b34801561056357600080fd5b506102cb610572366004614908565b600e602052600090815260409020546001600160a01b031681565b34801561059957600080fd5b506102f8610bdc565b3480156105ae57600080fd5b506102f8610bf1565b3480156105c357600080fd5b506102f8600081565b3480156105d857600080fd5b506104066105e7366004614925565b610c07565b3480156105f857600080fd5b506102f87f369da55721ba2b3acddd63aac7d6512c3e5762a78fa01c44f423f97868330c3481565b34801561062c57600080fd5b506102f8610c20565b34801561064157600080fd5b506102ab610650366004614d47565b610c35565b34801561066157600080fd5b50610276610670366004614e6a565b610d69565b6102ab610683366004614eb3565b610f7f565b34801561069457600080fd5b506102ab6106a3366004614f36565b610fc3565b3480156106b457600080fd5b506102f8611072565b3480156106c957600080fd5b506102f86106d8366004614925565b611087565b3480156106e957600080fd5b506102ab6106f836600461493e565b61109e565b34801561070957600080fd5b506004546102cb906001600160a01b031681565b34801561072957600080fd5b506102f87f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b34801561075d57600080fd5b5061078161076c366004614925565b600d6020526000908152604090205460ff1681565b6040516102829190614f98565b60006001600160e01b03198216635a05180f60e01b14806107b357506107b38261118f565b92915050565b60006107c4816111c4565b6107cd826111ce565b5050565b60405161215560f01b60208201526022015b6040516020818303038152906040528051906020012081565b604051605760f81b60208201526021016107e3565b604051602960f91b60208201526021016107e3565b604051614c4d60f01b60208201526022016107e3565b600082815260056020526040902060010154610857816111c4565b61086183836111f9565b505050565b6001600160a01b03811633146108db5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6107cd828261121b565b60006108f0816111c4565b6108f861123d565b50565b6003805461090890614fab565b80601f016020809104026020016040519081016040528092919081815260200182805461093490614fab565b80156109815780601f1061095657610100808354040283529160200191610981565b820191906000526020600020905b81548152906001019060200180831161096457829003601f168201915b505050505081565b60405161424d60f01b60208201526022016107e3565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e78cea926040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a189190614fea565b90506001600160a01b0381163314610a685760405162461bcd60e51b8152602060048201526013602482015272526f757465723a20627269646765206f6e6c7960681b60448201526064016108d2565b600a86905585610a7661128f565b610a8387878787876112e8565b610a8d6001600c55565b50506000600a555050600b805467ffffffffffffffff19169055505050565b60405161425560f01b60208201526022016107e3565b60405161557760f01b60208201526022016107e3565b6001600160a01b0381166000908152600860205260408120546107b3565b6000610b01816111c4565b6108f86113e5565b600060608082808083610b3d7f00000000000000000000000000000000000000000000000000000000000000006001611422565b610b687f00000000000000000000000000000000000000000000000000000000000000006002611422565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6000828152600660205260408120610baa90836114c6565b9392505050565b60009182526005602090815260408084206001600160a01b0393909316845291905290205460ff1690565b604051604160f81b60208201526021016107e3565b60405161214d60f01b60208201526022016107e3565b6009602052600090815260409020805461090890614fab565b604051600560fc1b60208201526021016107e3565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929610c5f816111c4565b815160005b81811015610d63576000848281518110610c8057610c80615007565b602002602001015160000151805190602001209050848281518110610ca757610ca7615007565b6020026020010151602001516007600083815260200190815260200160002060006101000a81548160ff0219169083151502179055507fbdb843232c6bb3b552562e583ff9dc6563aab189348ec5f43ef065b7393cd586858381518110610d1057610d10615007565b60200260200101516000015182878581518110610d2f57610d2f615007565b602002602001015160200151604051610d4a9392919061501d565b60405180910390a150610d5c8161505d565b9050610c64565b50505050565b60048054604080516373c6754960e11b8152905160009384936001600160a01b03169263e78cea9292818301926020928290030181865afa158015610db2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd69190614fea565b90506001600160a01b0381163314610e265760405162461bcd60e51b8152602060048201526013602482015272526f757465723a20627269646765206f6e6c7960681b60448201526064016108d2565b6004805460405163687f4b5760e11b81526001600160401b038616928101929092526000916001600160a01b039091169063d0fe96ae90602401602060405180830381865afa158015610e7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea19190614fea565b9050806001600160a01b0316856001600160a01b031614610efb5760405162461bcd60e51b81526020600482015260146024820152732937baba32b91d103bb937b7339039b2b73232b960611b60448201526064016108d2565b6001600160e01b03198616636b750d6360e01b14610f545760405162461bcd60e51b81526020600482015260166024820152752937baba32b91d103bb937b7339039b2b632b1ba37b960511b60448201526064016108d2565b50600b80546001600160401b03851667ffffffffffffffff1990911617905560019150509392505050565b600b805460ff60401b1916600160401b179055610f9a61128f565b610fa6848484846114d2565b610fb06001600c55565b5050600b805460ff60401b191690555050565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929610fed816111c4565b6001600160a01b0383166110435760405162461bcd60e51b815260206004820152601d60248201527f556e6966696564526f7574657256323a207a65726f206164647265737300000060448201526064016108d2565b506001600160a01b039182166000908152600e6020526040902080546001600160a01b03191691909216179055565b604051605360f81b60208201526021016107e3565b60008181526006602052604081206107b39061164c565b6000828152600560205260409020600101546110b9816111c4565b610861838361121b565b60006020835110156110df576110d883611656565b90506107b3565b816110ea84826150bc565b5060ff90506107b3565b6110fe8282610bb1565b6107cd5760008281526005602090815260408083206001600160a01b03851684529091529020805460ff191660011790556111363390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610baa836001600160a01b038416611694565b60006001600160e01b03198216637965db0b60e01b14806107b357506301ffc9a760e01b6001600160e01b03198316146107b3565b6108f881336116e3565b6111d78161173c565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b61120382826110f4565b6000828152600660205260409020610861908261117a565b611225828261178b565b600082815260066020526040902061086190826117f2565b611245611807565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6002600c54036112e15760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600c55565b61010082106113395760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a2077726f6e6720706172616d7320636f756e74000060448201526064016108d2565b805182146113595760405162461bcd60e51b81526004016108d29061517b565b80518460ff161061137c5760405162461bcd60e51b81526004016108d29061517b565b6000806000806113918860ff16888888611852565b93509350935093507f830adbcf80ee865e0f0883ad52e813fdbf061b0216b724694a2b4e06708d243c468a858786866040516113d2969594939291906151b2565b60405180910390a1505050505050505050565b6113ed611c3f565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586112723390565b606060ff8314611435576110d883611c85565b81805461144190614fab565b80601f016020809104026020016040519081016040528092919081815260200182805461146d90614fab565b80156114ba5780601f1061148f576101008083540402835291602001916114ba565b820191906000526020600020905b81548152906001019060200180831161149d57829003601f168201915b505050505090506107b3565b6000610baa8383611cc4565b61010083106115235760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a2077726f6e6720706172616d7320636f756e74000060448201526064016108d2565b815183146115435760405162461bcd60e51b81526004016108d29061517b565b600080611551868686611cee565b600082815260076020526040902054919350915060ff1615156001146115c75760405162461bcd60e51b815260206004820152602560248201527f42617365526f757465723a20636f6d706c6578206f70206e6f742072656769736044820152641d195c995960da1b60648201526084016108d2565b60006115d533848487611da7565b90506115e2843582611f5a565b5050506000806000806115f86000898989611852565b93509350935093507f830adbcf80ee865e0f0883ad52e813fdbf061b0216b724694a2b4e06708d243c4660008587868660405161163a969594939291906151b2565b60405180910390a15050505050505050565b60006107b3825490565b600080829050601f81511115611681578260405163305a27a960e01b81526004016108d291906149be565b805161168c826151fb565b179392505050565b60008181526001830160205260408120546116db575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107b3565b5060006107b3565b6116ed8282610bb1565b6107cd576116fa8161208f565b6117058360206120a1565b60405160200161171692919061521f565b60408051601f198184030181529082905262461bcd60e51b82526108d2916004016149be565b6001600160a01b0381166108f85760405162461bcd60e51b8152602060048201526016602482015275456e64506f696e743a207a65726f206164647265737360501b60448201526064016108d2565b6117958282610bb1565b156107cd5760008281526005602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610baa836001600160a01b03841661223c565b60005460ff166118505760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016108d2565b565b600080600080611860611c3f565b60408051606081018252600080825260208201819052918101919091526060895b88811015611c3157600a54611955901580159061189d57508b82145b8b8b848181106118af576118af615007565b90506020028101906118c19190615294565b6040516118cf9291906152da565b6040519081900390206118e360018d6152ea565b84106118f0576000611935565b8c8c6118fd8660016152fd565b81811061190c5761190c615007565b905060200281019061191e9190615294565b60405161192c9291906152da565b60405180910390205b8b858151811061194757611947615007565b60200260200101518761232f565b9298509196509093509150600085600281111561197457611974614f64565b14158a8a8381811061198857611988615007565b905060200281019061199a9190615294565b6040516020016119ab929190615310565b604051602081830303815290604052906119d85760405162461bcd60e51b81526004016108d291906149be565b5092508260028560028111156119f0576119f0614f64565b14611c31576001600160401b03861615611c21576004805460405163687f4b5760e11b81526001600160401b038916928101929092526000916001600160a01b039091169063d0fe96ae90602401602060405180830381865afa158015611a5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7f9190614fea565b9050611a8b81886128aa565b97508251600014611ab55782898381518110611aa957611aa9615007565b60200260200101819052505b6000636b750d6360e01b89848e8e8e604051602401611ad89594939291906153cd565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b0319909516949094179093526004805482516345d61ded60e01b815292519395506000946001600160a01b03909116936345d61ded9380840193908290030181865afa158015611b53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b779190614fea565b604051631d041f7b60e21b81529091506001600160a01b038216906374107dec90611bad90859087908e90600090600401615491565b600060405180830381600087803b158015611bc757600080fd5b505af1158015611bdb573d6000803e3d6000fd5b505050508a8481518110611bf157611bf1615007565b6020026020010151600960008c81526020019081526020016000209081611c1891906150bc565b50505050611c31565b611c2a8161505d565b9050611881565b505050945094509450949050565b60005460ff16156118505760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b60606000611c92836129dd565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000826000018281548110611cdb57611cdb615007565b9060005260206000200154905092915050565b600060608060005b85811015611d945781878783818110611d1157611d11615007565b9050602002810190611d239190615294565b604051602001611d35939291906154d6565b604051602081830303815290604052915082858281518110611d5957611d59615007565b6020026020010151604051602001611d729291906154fe565b604051602081830303815290604052925080611d8d9061505d565b9050611cf6565b5080516020909101209590945092505050565b600080611db386612a05565b905060007ff6ee28a1d07a7f08b92989953ec3452189f9f998ef0cb91641587f4f9a76c83b8783888888600001358960200135604051602001611dfc979695949392919061552d565b6040516020818303038152906040528051906020012090506000611e55611e2283612a2d565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b9050611e7a81611e6b6060880160408901615586565b87606001358860800135612a5a565b93508460200135421115611ec75760405162461bcd60e51b815260206004820152601460248201527342617365526f757465723a20646561646c696e6560601b60448201526064016108d2565b611ef17f369da55721ba2b3acddd63aac7d6512c3e5762a78fa01c44f423f97868330c3485610bb1565b611f4f5760405162461bcd60e51b815260206004820152602960248201527f42617365526f757465723a20696e76616c6964207369676e617475726520667260448201526837b6903bb7b935b2b960b91b60648201526084016108d2565b505050949350505050565b81341015611fa35760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881a5b9d985b1a5908185b5bdd5b9d60521b60448201526064016108d2565b6000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114611ff0576040519150601f19603f3d011682016040523d82523d6000602084013e611ff5565b606091505b50509050806120465760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a206661696c656420746f2073656e642045746865720000000060448201526064016108d2565b604080516001600160a01b03841681526020810185905233917fbf6afbaffb3b955bebbf43430bbf8eecb8d34ff86f293f592203ab5ed79c5268910160405180910390a2505050565b60606107b36001600160a01b03831660145b606060006120b08360026155a3565b6120bb9060026152fd565b6001600160401b038111156120d2576120d2614a2b565b6040519080825280601f01601f1916602001820160405280156120fc576020820181803683370190505b509050600360fc1b8160008151811061211757612117615007565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061214657612146615007565b60200101906001600160f81b031916908160001a905350600061216a8460026155a3565b6121759060016152fd565b90505b60018111156121ed576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106121a9576121a9615007565b1a60f81b8282815181106121bf576121bf615007565b60200101906001600160f81b031916908160001a90535060049490941c936121e6816155ba565b9050612178565b508315610baa5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016108d2565b600081815260018301602052604081205480156123255760006122606001836152ea565b8554909150600090612274906001906152ea565b90508181146122d957600086600001828154811061229457612294615007565b90600052602060002001549050808760000184815481106122b7576122b7615007565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806122ea576122ea6155d1565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107b3565b60009150506107b3565b604080516060818101835260008083526020830181905292820183905290600061235c8989898989612a84565b92965090945092509050600081600281111561237a5761237a614f64565b0361289e5750604051604160f81b60208201526001908890602101604051602081830303815290604052805190602001200361256c576000868060200190518101906123c691906156b0565b905060006123d7826080015161355f565b90506123f1826020015183604001518460e00151876135da565b6001600160a01b0390811660e08601819052911660408501526020840191909152606083015161242291468c6136ee565b6001600160a01b03166060830152815160408301516020840151612449929190849061380e565b806001600160a01b031663dc64ef4583600001518460200151856060015186608001518760a001518860c001518960e001516040518863ffffffff1660e01b815260040161249d97969594939291906156cd565b6020604051808303816000875af11580156124bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124e0919061570d565b80855260608301516001600160a01b03908116602087015260e084015116604086015260000361256557600b54600160401b900460ff16156125605760405162461bcd60e51b8152602060048201526019602482015278556e6966696564526f7574657256323a20736c69707061676560381b60448201526064016108d2565b600292505b505061289e565b604051602960f91b602082015288906021016040516020818303038152906040528051906020012003612686576000868060200190518101906125af91906156b0565b905060006125c0826080015161355f565b90506125da826020015183604001518460e00151876135da565b6001600160a01b0390811660e08601819052911660408501526020840191909152606083015161260b91468c6136ee565b6001600160a01b03166060830152815160408301516020840151612632929190849061380e565b806001600160a01b031663cd7bfd5883600001518460200151856060015186608001518760a001518860c001518960e001516040518863ffffffff1660e01b815260040161249d97969594939291906156cd565b604051605360f81b60208201528890602101604051602081830303815290604052805190602001200361289a576000868060200190518101906126c99190615726565b905060006126da826080015161355f565b90506126f582602001518360400151846101000151876135da565b6001600160a01b039081166101008601819052911660408501526020840191909152606083015161272791468c6136ee565b6001600160a01b0316606083015281516040830151602084015161274e929190849061380e565b815160208301516060840151608085015160a086015160c087015160e0880151610100890151604051636469c44f60e01b81526001600160a01b039889166004820152602481019790975294871660448701529286166064860152608485019190915260ff90811660a48501521660c4830152821660e482015290821690636469c44f90610104016020604051808303816000875af11580156127f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612819919061570d565b80855260608301516001600160a01b03908116602087015261010084015116604086015260000361256557600b54600160401b900460ff16156125605760405162461bcd60e51b8152602060048201526019602482015278556e6966696564526f7574657256323a20736c69707061676560381b60448201526064016108d2565b5060005b95509550955095915050565b60048054604080516345d61ded60e01b8152905160009384936001600160a01b0316926345d61ded92818301926020928290030181865afa1580156128f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129179190614fea565b90506000816001600160a01b031663d087d2886040518163ffffffff1660e01b8152600401602060405180830381865afa158015612959573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061297d919061570d565b60408051306020808301919091528183018490526001600160401b03881660608301524660808301526001600160a01b03891660a0808401919091528351808403909101815260c090920190925280519101209091505b95945050505050565b600060ff8216601f8111156107b357604051632cd44ac360e21b815260040160405180910390fd5b6001600160a01b03811660009081526008602052604090208054600181018255905b50919050565b60006107b3612a3a61383a565b8360405161190160f01b8152600281019290925260228201526042902090565b6000806000612a6b8787878761396a565b91509150612a7881613a2e565b5090505b949350505050565b604080516060818101835260008083526020830181905292820183905290604051600560fc1b602082015260019088906021016040516020818303038152906040528051906020012003612b9657600086806020019051810190612ae891906157ce565b805160208201516040808401516060850151608086015160a087015160c0880151945163d505accf60e01b81526001600160a01b0396871660048201523060248201526044810194909452606484019290925260ff16608483015260a482015260c4810191909152929350169063d505accf9060e401600060405180830381600087803b158015612b7857600080fd5b505af1158015612b8c573d6000803e3d6000fd5b505050505061289e565b604051614c4d60f01b60208201528890602201604051602081830303815290604052805190602001201480612bf1575060405161425560f01b6020820152889060220160405160208183030381529060405280519060200120145b80612c22575060405161424d60f01b6020820152889060220160405160208183030381529060405280519060200120145b1561319957600086806020019051810190612c3d919061584e565b905089151560000361306c57612c61816020015182604001518360c00151896135da565b6001600160a01b0390811660c0850181905291166040840152602083019190915260608201516080830151612c9792908b6136ee565b6001600160a01b03166060820152604051614c4d60f01b60208201526000908a906022016040516020818303038152906040528051906020012003612ce457612cdf82613b78565b612ea9565b6004805460405163d4f0cceb60e01b81526001600160401b034616928101929092526000916001600160a01b039091169063d4f0cceb90602401602060405180830381865afa158015612d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5f9190614fea565b83516040516305b338c160e21b81526001600160a01b0391821660048201529192508216906316cce30490602401602060405180830381865afa158015612daa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dce9190614fea565b91506001600160a01b03821615612e2857806001600160a01b031683604001516001600160a01b031614612e1457612e1483600001518460400151838660200151613ca2565b6001600160a01b0381166040840152612e2d565b825191505b806001600160a01b031663b6ff156a846000015185602001518660400151876060015188608001516040518663ffffffff1660e01b8152600401612e759594939291906158e5565b600060405180830381600087803b158015612e8f57600080fd5b505af1158015612ea3573d6000803e3d6000fd5b50505050505b8160800151955089604051602001612ec990614c4d60f01b815260020190565b6040516020818303038152906040528051906020012014612fcf576000819050806001600160a01b0316630e7c1cb56040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f4b9190614fea565b6001600160a01b039081168452604080516306ed82dd60e31b815290519183169163376c16e8916004808201926020929091908290030181865afa158015612f97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbb9190615920565b6001600160401b031660a084015250612fdf565b6001600160401b03461660a08301525b81604051602001613055919081516001600160a01b039081168252602080840151908301526040808401518216908301526060808401518216908301526080808401516001600160401b039081169184019190915260a0848101519091169083015260c092830151169181019190915260e00190565b604051602081830303815290604052945050613193565b600a546000908152600d602052604081205460ff16600281111561309257613092614f64565b146130d65760405162461bcd60e51b8152602060048201526014602482015273149bdd5d195c8e881bdc081c1c9bd8d95cdcd95960621b60448201526064016108d2565b600a546000908152600d60205260409020805460ff1916600117905560608101516001600160a01b031661312b5761311c81606001518260c0015183608001518b6136ee565b6001600160a01b031660608201525b60405161425560f01b6020820152899060220160405160208183030381529060405280519060200120146131675761316281613d0d565b613170565b61317081613e14565b835260608101516001600160a01b03908116602085015260c08201511660408401525b5061289e565b604051605760f81b602082015288906021016040516020818303038152906040528051906020012014806131f3575060405161557760f01b6020820152889060220160405160208183030381529060405280519060200120145b156132ce5760008680602001905181019061320e919061593d565b905060006132278260200151836040015160008a6135da565b6001600160a01b039091166040850152602084019190915260608301519091506132539080468c6136ee565b6001600160a01b03166060830152604051605760f81b60208201528a90602101604051602081830303815290604052805190602001201461329c5761329782613ed2565b6132a5565b6132a58261401d565b845250606001516001600160a01b0390811660208401526040868101519091169083015261289e565b60405161214d60f01b60208201528890602201604051602081830303815290604052805190602001201480613329575060405161215560f01b6020820152889060220160405160208183030381529060405280519060200120145b1561354d5760008680602001905181019061334491906159b8565b90508915156000036133e357600181516000908152600d602052604090205460ff16600281111561337757613377614f64565b036133bb5760405162461bcd60e51b8152602060048201526014602482015273149bdd5d195c8e881bdc081c1c9bd8d95cdcd95960621b60448201526064016108d2565b80516000908152600d60209081526040909120805460ff191660021790558101519450613193565b8051600090815260096020526040812080546133fe90614fab565b80601f016020809104026020016040519081016040528092919081815260200182805461342a90614fab565b80156134775780601f1061344c57610100808354040283529160200191613477565b820191906000526020600020905b81548152906001019060200180831161345a57829003601f168201915b5050505050905080516000036134c85760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881bdc081b9bdd081cdd185c9d195960521b60448201526064016108d2565b6000818060200190518101906134de919061584e565b835160009081526009602052604081209192506134fb9190614872565b60405161214d60f01b60208201528b90602201604051602081830303815290604052805190602001200361353957613532816140e7565b8552613545565b6135428161420a565b85525b50505061289e565b50839050600095509550955095915050565b6001600160a01b038082166000908152600e602052604090205416806135d55760405162461bcd60e51b815260206004820152602560248201527f556e6966696564526f7574657256323a20706f6f6c2061646170746572206e6f6044820152641d081cd95d60da1b60648201526084016108d2565b919050565b600080600060001987146135ee57866135f1565b83515b92506001600160a01b03861615613659576001600160a01b03861633146136515760405162461bcd60e51b81526020600482015260146024820152732937baba32b91d103bb937b7339039b2b73232b960611b60448201526064016108d2565b859150613661565b836020015191505b600a5415801561367957506001600160a01b03851615155b156136dd576001600160a01b03851633146136d65760405162461bcd60e51b815260206004820152601960248201527f526f757465723a2077726f6e6720656d657267656e6379546f0000000000000060448201526064016108d2565b50836136e4565b5060408301515b9450945094915050565b60006136fc858585856143b4565b90506001600160a01b038116612a7c57604051604160f81b6020820152602101604051602081830303815290604052805190602001208214806137635750604051602960f91b60208201526021016040516020818303038152906040528051906020012082145b806137925750604051605360f81b60208201526021016040516020818303038152906040528051906020012082145b15612a7c576004805460405163687f4b5760e11b81526001600160401b038616928101929092526001600160a01b03169063d0fe96ae906024015b602060405180830381865afa1580156137ea573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129d49190614fea565b306001600160a01b0384160361382e5761382984838361464a565b610d63565b610d6384848484613ca2565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561389357507f000000000000000000000000000000000000000000000000000000000000000046145b156138bd57507f000000000000000000000000000000000000000000000000000000000000000090565b613965604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156139a15750600090506003613a25565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156139f5573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613a1e57600060019250925050613a25565b9150600090505b94509492505050565b6000816004811115613a4257613a42614f64565b03613a4a5750565b6001816004811115613a5e57613a5e614f64565b03613aab5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016108d2565b6002816004811115613abf57613abf614f64565b03613b0c5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016108d2565b6003816004811115613b2057613b20614f64565b036108f85760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016108d2565b60048054604051630f5427af60e41b81526001600160401b034616928101929092526000916001600160a01b039091169063f5427af090602401602060405180830381865afa158015613bcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bf39190614fea565b9050806001600160a01b031682604001516001600160a01b031614613c2a57613c2a82600001518360400151838560200151613ca2565b806001600160a01b0316633fea56b883600001518460200151856040015186606001516040518563ffffffff1660e01b8152600401613c6c9493929190615a0d565b600060405180830381600087803b158015613c8657600080fd5b505af1158015613c9a573d6000803e3d6000fd5b505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052610d639085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261467a565b6004805460405163d4f0cceb60e01b81526001600160401b0346169281019290925260009182916001600160a01b03169063d4f0cceb90602401602060405180830381865afa158015613d64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d889190614fea565b83516020850151604080870151606088015160a0890151925163df543e8160e01b81529596506001600160a01b0387169563df543e8195613dd1959094909392916004016158e5565b6020604051808303816000875af1158015613df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610baa919061570d565b60048054604051630f5427af60e41b81526001600160401b0346169281019290925260009182916001600160a01b03169063f5427af090602401602060405180830381865afa158015613e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e8f9190614fea565b8351602085015160408087015160608801519151637f27a5b960e11b81529495506001600160a01b0386169463fe4f4b7294613dd1949093909291600401615a0d565b60408101516000906001600160a01b03163014613f0157613f0182600001518360400151308560200151613ca2565b81516020830151604051632e1a7d4d60e01b81526001600160a01b0390921691632e1a7d4d91613f379160040190815260200190565b600060405180830381600087803b158015613f5157600080fd5b505af1158015613f65573d6000803e3d6000fd5b50505050600082606001516001600160a01b0316836020015160405160006040518083038185875af1925050503d8060008114613fbe576040519150601f19603f3d011682016040523d82523d6000602084013e613fc3565b606091505b50509050806140145760405162461bcd60e51b815260206004820152601a60248201527f526f757465723a206661696c656420746f2073656e642045544800000000000060448201526064016108d2565b50506020015190565b6000816020015134101561406c5760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881a5b9d985b1a5908185b5bdd5b9d60521b60448201526064016108d2565b81600001516001600160a01b031663d0e30db083602001516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156140af57600080fd5b505af11580156140c3573d6000803e3d6000fd5b50505050506140df82600001518360600151846020015161464a565b506020015190565b6080810151600b546000916001600160401b0391821691161461414c5760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a2077726f6e6720656d657267656e637920696e69740000000060448201526064016108d2565b60048054604051630f5427af60e41b81526001600160401b034616928101929092526000916001600160a01b039091169063f5427af090602401602060405180830381865afa1580156141a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c79190614fea565b8351602085015160408087015160c0880151915163c26b5bab60e01b81529495506001600160a01b0386169463c26b5bab94613dd1949093909291600401615a0d565b6080810151600b546000916001600160401b0391821691161461426f5760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a2077726f6e6720656d657267656e637920696e69740000000060448201526064016108d2565b6004805460405163d4f0cceb60e01b81526001600160401b034616928101929092526000916001600160a01b039091169063d4f0cceb90602401602060405180830381865afa1580156142c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142ea9190614fea565b60a08401518451604051637f9fa89f60e01b81526001600160401b0390921660048301526001600160a01b03908116602483015291925090821690637f9fa89f90604401602060405180830381865afa15801561434b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061436f9190614fea565b6001600160a01b03908116808552602085015160408087015160c0880151915163550bf7db60e11b81529486169463aa17efb694613dd1949093909291600401615a0d565b60006001600160a01b03851615806143ca575081155b6144095760405162461bcd60e51b815260206004820152601060248201526f526f757465723a2077726f6e6720746f60801b60448201526064016108d2565b8161447057849050836001600160a01b0316816001600160a01b03161461446b5760405162461bcd60e51b81526020600482015260166024820152752937baba32b91d103bb937b733903932b1b2b4bb32b960511b60448201526064016108d2565b612a7c565b604051614c4d60f01b602082015260220160405160208183030381529060405280519060200120820361451b5760048054604051630f5427af60e41b81526001600160401b038616928101929092526001600160a01b03169063f5427af0906024015b602060405180830381865afa1580156144f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145149190614fea565b9050612a7c565b60405161425560f01b602082015260220160405160208183030381529060405280519060200120821480614574575060405161424d60f01b60208201526022016040516020818303038152906040528051906020012082145b156145b3576004805460405163d4f0cceb60e01b81526001600160401b038616928101929092526001600160a01b03169063d4f0cceb906024016144d3565b604051605760f81b60208201528290602101604051602081830303815290604052805190602001201480613792575060405161557760f01b602082015282906022016040516020818303038152906040528051906020012003612a7c576004805460405163687f4b5760e11b81526001600160401b038616928101929092526001600160a01b03169063d0fe96ae906024016137cd565b6040516001600160a01b03831660248201526044810182905261086190849063a9059cbb60e01b90606401613cd6565b60006146cf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661474f9092919063ffffffff16565b90508051600014806146f05750808060200190518101906146f09190615a38565b6108615760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016108d2565b6060612a7c848460008585600080866001600160a01b031685876040516147769190615a55565b60006040518083038185875af1925050503d80600081146147b3576040519150601f19603f3d011682016040523d82523d6000602084013e6147b8565b606091505b50915091506147c9878383876147d4565b979650505050505050565b6060831561484357825160000361483c576001600160a01b0385163b61483c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108d2565b5081612a7c565b612a7c83838151156148585781518083602001fd5b8060405162461bcd60e51b81526004016108d291906149be565b50805461487e90614fab565b6000825580601f1061488e575050565b601f0160209004906000526020600020908101906108f891905b808211156148bc57600081556001016148a8565b5090565b80356001600160e01b0319811681146135d557600080fd5b6000602082840312156148ea57600080fd5b610baa826148c0565b6001600160a01b03811681146108f857600080fd5b60006020828403121561491a57600080fd5b8135610baa816148f3565b60006020828403121561493757600080fd5b5035919050565b6000806040838503121561495157600080fd5b823591506020830135614963816148f3565b809150509250929050565b60005b83811015614989578181015183820152602001614971565b50506000910152565b600081518084526149aa81602086016020860161496e565b601f01601f19169290920160200192915050565b602081526000610baa6020830184614992565b60ff811681146108f857600080fd5b60008083601f8401126149f257600080fd5b5081356001600160401b03811115614a0957600080fd5b6020830191508360208260051b8501011115614a2457600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715614a6357614a63614a2b565b60405290565b60405161012081016001600160401b0381118282101715614a6357614a63614a2b565b60405160e081016001600160401b0381118282101715614a6357614a63614a2b565b604051601f8201601f191681016001600160401b0381118282101715614ad657614ad6614a2b565b604052919050565b60006001600160401b03821115614af757614af7614a2b565b5060051b60200190565b60006001600160401b03831115614b1a57614b1a614a2b565b614b2d601f8401601f1916602001614aae565b9050828152838383011115614b4157600080fd5b828260208301376000602084830101529392505050565b600082601f830112614b6957600080fd5b81356020614b7e614b7983614ade565b614aae565b82815260059290921b84018101918181019086841115614b9d57600080fd5b8286015b84811015614bf15780356001600160401b03811115614bc05760008081fd5b8701603f81018913614bd25760008081fd5b614be3898683013560408401614b01565b845250918301918301614ba1565b509695505050505050565b600080600080600060808688031215614c1457600080fd5b853594506020860135614c26816149d1565b935060408601356001600160401b0380821115614c4257600080fd5b614c4e89838a016149e0565b90955093506060880135915080821115614c6757600080fd5b50614c7488828901614b58565b9150509295509295909350565b60ff60f81b881681526000602060e081840152614ca160e084018a614992565b8381036040850152614cb3818a614992565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015614d0557835183529284019291840191600101614ce9565b50909c9b505050505050505050505050565b60008060408385031215614d2a57600080fd5b50508035926020909101359150565b80151581146108f857600080fd5b60006020808385031215614d5a57600080fd5b82356001600160401b0380821115614d7157600080fd5b818501915085601f830112614d8557600080fd5b8135614d93614b7982614ade565b81815260059190911b83018401908481019088831115614db257600080fd5b8585015b83811015614e4857803585811115614dce5760008081fd5b86016040818c03601f1901811315614de65760008081fd5b614dee614a41565b8983013588811115614e005760008081fd5b8301603f81018e13614e125760008081fd5b614e228e8c830135858401614b01565b8252509181013591614e3383614d39565b808a0192909252508352918601918601614db6565b5098975050505050505050565b6001600160401b03811681146108f857600080fd5b600080600060608486031215614e7f57600080fd5b614e88846148c0565b92506020840135614e98816148f3565b91506040840135614ea881614e55565b809150509250925092565b60008060008084860360e0811215614eca57600080fd5b85356001600160401b0380821115614ee157600080fd5b614eed89838a016149e0565b90975095506020880135915080821115614f0657600080fd5b50614f1388828901614b58565b93505060a0603f1982011215614f2857600080fd5b509295919450926040019150565b60008060408385031215614f4957600080fd5b8235614f54816148f3565b91506020830135614963816148f3565b634e487b7160e01b600052602160045260246000fd5b600381106108f857634e487b7160e01b600052602160045260246000fd5b60208101614fa583614f7a565b91905290565b600181811c90821680614fbf57607f821691505b602082108103612a2757634e487b7160e01b600052602260045260246000fd5b80516135d5816148f3565b600060208284031215614ffc57600080fd5b8151610baa816148f3565b634e487b7160e01b600052603260045260246000fd5b6060815260006150306060830186614992565b602083019490945250901515604090910152919050565b634e487b7160e01b600052601160045260246000fd5b60006001820161506f5761506f615047565b5060010190565b601f82111561086157600081815260208120601f850160051c8101602086101561509d5750805b601f850160051c820191505b81811015613c9a578281556001016150a9565b81516001600160401b038111156150d5576150d5614a2b565b6150e9816150e38454614fab565b84615076565b602080601f83116001811461511e57600084156151065750858301515b600019600386901b1c1916600185901b178555613c9a565b600085815260208120601f198616915b8281101561514d5788860151825594840194600190910190840161512e565b508582101561516b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60208082526018908201527f42617365526f757465723a2077726f6e6720706172616d730000000000000000604082015260600190565b6001600160401b03878116825260208201879052851660408201526060810184905260c081016151e184614f7a565b83608083015260ff831660a0830152979650505050505050565b80516020808301519190811015612a275760001960209190910360031b1b16919050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161525781601785016020880161496e565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161528881602884016020880161496e565b01602801949350505050565b6000808335601e198436030181126152ab57600080fd5b8301803591506001600160401b038211156152c557600080fd5b602001915036819003821315614a2457600080fd5b8183823760009101908152919050565b818103818111156107b3576107b3615047565b808201808211156107b3576107b3615047565b6a02937baba32b91d1037b8160ad1b81528183600b83013770081a5cc81b9bdd081cdd5c1c1bdc9d1959607a1b9101600b810191909152601c01919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526020808501808196508360051b8101915082860160005b858110156153c05782840389526153ae848351614992565b98850198935090840190600101615396565b5091979650505050505050565b600060808201878352602060ff881681850152608060408501528186835260a08501905060a08760051b86010192508760005b8881101561546f57868503609f190183528135368b9003601e1901811261542657600080fd5b8a0184810190356001600160401b0381111561544157600080fd5b80360382131561545057600080fd5b61545b87828461534f565b965050509183019190830190600101615400565b5050505082810360608401526154858185615378565b98975050505050505050565b6080815260006154a46080830187614992565b6001600160a01b0395861660208401526001600160401b03949094166040830152509216606090920191909152919050565b600084516154e881846020890161496e565b8201838582376000930192835250909392505050565b6000835161551081846020880161496e565b83519083019061552481836020880161496e565b01949350505050565b8781526bffffffffffffffffffffffff198760601b1660208201528560348201528460548201526000845161556981607485016020890161496e565b909101607481019390935250609482015260b40195945050505050565b60006020828403121561559857600080fd5b8135610baa816149d1565b80820281158282048414176107b3576107b3615047565b6000816155c9576155c9615047565b506000190190565b634e487b7160e01b600052603160045260246000fd5b80516135d5816149d1565b600061010080838503121561560657600080fd5b604051908101906001600160401b038211818310171561562857615628614a2b565b816040528092508351915061563c826148f3565b8181526020840151602082015261565560408501614fdf565b604082015261566660608501614fdf565b606082015261567760808501614fdf565b608082015260a084015160a082015261569260c085016155e7565b60c08201526156a360e08501614fdf565b60e0820152505092915050565b600061010082840312156156c357600080fd5b610baa83836155f2565b6001600160a01b039788168152602081019690965293861660408601529185166060850152608084015260ff1660a083015290911660c082015260e00190565b60006020828403121561571f57600080fd5b5051919050565b6000610120828403121561573957600080fd5b615741614a69565b61574a83614fdf565b81526020830151602082015261576260408401614fdf565b604082015261577360608401614fdf565b606082015261578460808401614fdf565b608082015260a083015160a082015261579f60c084016155e7565b60c08201526157b060e084016155e7565b60e08201526101006157c3818501614fdf565b908201529392505050565b600060e082840312156157e057600080fd5b6157e8614a8c565b82516157f3816148f3565b81526020830151615803816148f3565b806020830152506040830151604082015260608301516060820152608083015161582c816149d1565b608082015260a0838101519082015260c0928301519281019290925250919050565b600060e0828403121561586057600080fd5b615868614a8c565b8251615873816148f3565b815260208381015190820152604083015161588d816148f3565b604082015260608301516158a0816148f3565b606082015260808301516158b381614e55565b608082015260a08301516158c681614e55565b60a082015260c08301516158d9816148f3565b60c08201529392505050565b6001600160a01b0395861681526020810194909452918416604084015290921660608201526001600160401b03909116608082015260a00190565b60006020828403121561593257600080fd5b8151610baa81614e55565b60006080828403121561594f57600080fd5b604051608081018181106001600160401b038211171561597157615971614a2b565b604052825161597f816148f3565b8152602083810151908201526040830151615999816148f3565b604082015260608301516159ac816148f3565b60608201529392505050565b6000604082840312156159ca57600080fd5b604051604081018181106001600160401b03821117156159ec576159ec614a2b565b604052825181526020830151615a0181614e55565b60208201529392505050565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b600060208284031215615a4a57600080fd5b8151610baa81614d39565b60008251615a6781846020870161496e565b919091019291505056fea2646970667358221220536cace6d8a04a3954633ca623643535b8a2560e5c4e4682ca9ccaa70fd0f0ff64736f6c63430008110033000000000000000000000000564a0c04877e4ca6f5d0cad8c20522226321d9b0
Deployed Bytecode
0x60806040526004361061024a5760003560e01c80638456cb5911610139578063ad351f9f116100b6578063beadbe321161007a578063beadbe32146106a8578063ca15c873146106bd578063d547741f146106dd578063f5887cdd146106fd578063f5b541a61461071d578063f87cf42b1461075157600080fd5b8063ad351f9f14610620578063b2e1df7214610635578063b4ccca0d14610655578063ba677db714610675578063bcf4f0a61461068857600080fd5b80639ba520ad116100fd5780639ba520ad1461058d5780639bb68c75146105a2578063a217fddf146105b7578063a785ac5a146105cc578063ab1efbab146105ec57600080fd5b80638456cb59146104da57806384b0196e146104ef5780639010d07c1461051757806391d148541461053757806395ad709a1461055757600080fd5b80633e7e25c1116101c7578063692a34f41161018b578063692a34f4146104405780636b750d631461047057806376a3fb3e14610490578063778c89b9146104a55780637ecebe00146104ba57600080fd5b80633e7e25c1146103b55780633f4ba83a146103dc57806354fd4d50146103f15780635c975abb146104135780636869cb961461042b57600080fd5b80632b385bcf1161020e5780632b385bcf146103365780632d07ae691461034b5780632ee63e44146103605780632f2ff15d1461037557806336568abe1461039557600080fd5b806301ffc9a7146102565780630b3448a81461028b5780630e03e490146102ad5780630ff53ba7146102e3578063248a9ca31461030657600080fd5b3661025157005b600080fd5b34801561026257600080fd5b506102766102713660046148d8565b61078e565b60405190151581526020015b60405180910390f35b34801561029757600080fd5b506102ab6102a6366004614908565b6107b9565b005b3480156102b957600080fd5b506102cb6102c8366004614925565b90565b6040516001600160a01b039091168152602001610282565b3480156102ef57600080fd5b506102f86107d1565b604051908152602001610282565b34801561031257600080fd5b506102f8610321366004614925565b60009081526005602052604090206001015490565b34801561034257600080fd5b506102f86107fc565b34801561035757600080fd5b506102f8610811565b34801561036c57600080fd5b506102f8610826565b34801561038157600080fd5b506102ab61039036600461493e565b61083c565b3480156103a157600080fd5b506102ab6103b036600461493e565b610866565b3480156103c157600080fd5b506102f86103d0366004614908565b6001600160a01b031690565b3480156103e857600080fd5b506102ab6108e5565b3480156103fd57600080fd5b506104066108fb565b60405161028291906149be565b34801561041f57600080fd5b5060005460ff16610276565b34801561043757600080fd5b506102f8610989565b34801561044c57600080fd5b5061027661045b366004614925565b60076020526000908152604090205460ff1681565b34801561047c57600080fd5b506102ab61048b366004614bfc565b61099f565b34801561049c57600080fd5b506102f8610aac565b3480156104b157600080fd5b506102f8610ac2565b3480156104c657600080fd5b506102f86104d5366004614908565b610ad8565b3480156104e657600080fd5b506102ab610af6565b3480156104fb57600080fd5b50610504610b09565b6040516102829796959493929190614c81565b34801561052357600080fd5b506102cb610532366004614d17565b610b92565b34801561054357600080fd5b5061027661055236600461493e565b610bb1565b34801561056357600080fd5b506102cb610572366004614908565b600e602052600090815260409020546001600160a01b031681565b34801561059957600080fd5b506102f8610bdc565b3480156105ae57600080fd5b506102f8610bf1565b3480156105c357600080fd5b506102f8600081565b3480156105d857600080fd5b506104066105e7366004614925565b610c07565b3480156105f857600080fd5b506102f87f369da55721ba2b3acddd63aac7d6512c3e5762a78fa01c44f423f97868330c3481565b34801561062c57600080fd5b506102f8610c20565b34801561064157600080fd5b506102ab610650366004614d47565b610c35565b34801561066157600080fd5b50610276610670366004614e6a565b610d69565b6102ab610683366004614eb3565b610f7f565b34801561069457600080fd5b506102ab6106a3366004614f36565b610fc3565b3480156106b457600080fd5b506102f8611072565b3480156106c957600080fd5b506102f86106d8366004614925565b611087565b3480156106e957600080fd5b506102ab6106f836600461493e565b61109e565b34801561070957600080fd5b506004546102cb906001600160a01b031681565b34801561072957600080fd5b506102f87f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b34801561075d57600080fd5b5061078161076c366004614925565b600d6020526000908152604090205460ff1681565b6040516102829190614f98565b60006001600160e01b03198216635a05180f60e01b14806107b357506107b38261118f565b92915050565b60006107c4816111c4565b6107cd826111ce565b5050565b60405161215560f01b60208201526022015b6040516020818303038152906040528051906020012081565b604051605760f81b60208201526021016107e3565b604051602960f91b60208201526021016107e3565b604051614c4d60f01b60208201526022016107e3565b600082815260056020526040902060010154610857816111c4565b61086183836111f9565b505050565b6001600160a01b03811633146108db5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6107cd828261121b565b60006108f0816111c4565b6108f861123d565b50565b6003805461090890614fab565b80601f016020809104026020016040519081016040528092919081815260200182805461093490614fab565b80156109815780601f1061095657610100808354040283529160200191610981565b820191906000526020600020905b81548152906001019060200180831161096457829003601f168201915b505050505081565b60405161424d60f01b60208201526022016107e3565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e78cea926040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a189190614fea565b90506001600160a01b0381163314610a685760405162461bcd60e51b8152602060048201526013602482015272526f757465723a20627269646765206f6e6c7960681b60448201526064016108d2565b600a86905585610a7661128f565b610a8387878787876112e8565b610a8d6001600c55565b50506000600a555050600b805467ffffffffffffffff19169055505050565b60405161425560f01b60208201526022016107e3565b60405161557760f01b60208201526022016107e3565b6001600160a01b0381166000908152600860205260408120546107b3565b6000610b01816111c4565b6108f86113e5565b600060608082808083610b3d7f45595741000000000000000000000000000000000000000000000000000000046001611422565b610b687f31000000000000000000000000000000000000000000000000000000000000016002611422565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6000828152600660205260408120610baa90836114c6565b9392505050565b60009182526005602090815260408084206001600160a01b0393909316845291905290205460ff1690565b604051604160f81b60208201526021016107e3565b60405161214d60f01b60208201526022016107e3565b6009602052600090815260409020805461090890614fab565b604051600560fc1b60208201526021016107e3565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929610c5f816111c4565b815160005b81811015610d63576000848281518110610c8057610c80615007565b602002602001015160000151805190602001209050848281518110610ca757610ca7615007565b6020026020010151602001516007600083815260200190815260200160002060006101000a81548160ff0219169083151502179055507fbdb843232c6bb3b552562e583ff9dc6563aab189348ec5f43ef065b7393cd586858381518110610d1057610d10615007565b60200260200101516000015182878581518110610d2f57610d2f615007565b602002602001015160200151604051610d4a9392919061501d565b60405180910390a150610d5c8161505d565b9050610c64565b50505050565b60048054604080516373c6754960e11b8152905160009384936001600160a01b03169263e78cea9292818301926020928290030181865afa158015610db2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd69190614fea565b90506001600160a01b0381163314610e265760405162461bcd60e51b8152602060048201526013602482015272526f757465723a20627269646765206f6e6c7960681b60448201526064016108d2565b6004805460405163687f4b5760e11b81526001600160401b038616928101929092526000916001600160a01b039091169063d0fe96ae90602401602060405180830381865afa158015610e7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea19190614fea565b9050806001600160a01b0316856001600160a01b031614610efb5760405162461bcd60e51b81526020600482015260146024820152732937baba32b91d103bb937b7339039b2b73232b960611b60448201526064016108d2565b6001600160e01b03198616636b750d6360e01b14610f545760405162461bcd60e51b81526020600482015260166024820152752937baba32b91d103bb937b7339039b2b632b1ba37b960511b60448201526064016108d2565b50600b80546001600160401b03851667ffffffffffffffff1990911617905560019150509392505050565b600b805460ff60401b1916600160401b179055610f9a61128f565b610fa6848484846114d2565b610fb06001600c55565b5050600b805460ff60401b191690555050565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929610fed816111c4565b6001600160a01b0383166110435760405162461bcd60e51b815260206004820152601d60248201527f556e6966696564526f7574657256323a207a65726f206164647265737300000060448201526064016108d2565b506001600160a01b039182166000908152600e6020526040902080546001600160a01b03191691909216179055565b604051605360f81b60208201526021016107e3565b60008181526006602052604081206107b39061164c565b6000828152600560205260409020600101546110b9816111c4565b610861838361121b565b60006020835110156110df576110d883611656565b90506107b3565b816110ea84826150bc565b5060ff90506107b3565b6110fe8282610bb1565b6107cd5760008281526005602090815260408083206001600160a01b03851684529091529020805460ff191660011790556111363390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610baa836001600160a01b038416611694565b60006001600160e01b03198216637965db0b60e01b14806107b357506301ffc9a760e01b6001600160e01b03198316146107b3565b6108f881336116e3565b6111d78161173c565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b61120382826110f4565b6000828152600660205260409020610861908261117a565b611225828261178b565b600082815260066020526040902061086190826117f2565b611245611807565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6002600c54036112e15760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600c55565b61010082106113395760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a2077726f6e6720706172616d7320636f756e74000060448201526064016108d2565b805182146113595760405162461bcd60e51b81526004016108d29061517b565b80518460ff161061137c5760405162461bcd60e51b81526004016108d29061517b565b6000806000806113918860ff16888888611852565b93509350935093507f830adbcf80ee865e0f0883ad52e813fdbf061b0216b724694a2b4e06708d243c468a858786866040516113d2969594939291906151b2565b60405180910390a1505050505050505050565b6113ed611c3f565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586112723390565b606060ff8314611435576110d883611c85565b81805461144190614fab565b80601f016020809104026020016040519081016040528092919081815260200182805461146d90614fab565b80156114ba5780601f1061148f576101008083540402835291602001916114ba565b820191906000526020600020905b81548152906001019060200180831161149d57829003601f168201915b505050505090506107b3565b6000610baa8383611cc4565b61010083106115235760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a2077726f6e6720706172616d7320636f756e74000060448201526064016108d2565b815183146115435760405162461bcd60e51b81526004016108d29061517b565b600080611551868686611cee565b600082815260076020526040902054919350915060ff1615156001146115c75760405162461bcd60e51b815260206004820152602560248201527f42617365526f757465723a20636f6d706c6578206f70206e6f742072656769736044820152641d195c995960da1b60648201526084016108d2565b60006115d533848487611da7565b90506115e2843582611f5a565b5050506000806000806115f86000898989611852565b93509350935093507f830adbcf80ee865e0f0883ad52e813fdbf061b0216b724694a2b4e06708d243c4660008587868660405161163a969594939291906151b2565b60405180910390a15050505050505050565b60006107b3825490565b600080829050601f81511115611681578260405163305a27a960e01b81526004016108d291906149be565b805161168c826151fb565b179392505050565b60008181526001830160205260408120546116db575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107b3565b5060006107b3565b6116ed8282610bb1565b6107cd576116fa8161208f565b6117058360206120a1565b60405160200161171692919061521f565b60408051601f198184030181529082905262461bcd60e51b82526108d2916004016149be565b6001600160a01b0381166108f85760405162461bcd60e51b8152602060048201526016602482015275456e64506f696e743a207a65726f206164647265737360501b60448201526064016108d2565b6117958282610bb1565b156107cd5760008281526005602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610baa836001600160a01b03841661223c565b60005460ff166118505760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016108d2565b565b600080600080611860611c3f565b60408051606081018252600080825260208201819052918101919091526060895b88811015611c3157600a54611955901580159061189d57508b82145b8b8b848181106118af576118af615007565b90506020028101906118c19190615294565b6040516118cf9291906152da565b6040519081900390206118e360018d6152ea565b84106118f0576000611935565b8c8c6118fd8660016152fd565b81811061190c5761190c615007565b905060200281019061191e9190615294565b60405161192c9291906152da565b60405180910390205b8b858151811061194757611947615007565b60200260200101518761232f565b9298509196509093509150600085600281111561197457611974614f64565b14158a8a8381811061198857611988615007565b905060200281019061199a9190615294565b6040516020016119ab929190615310565b604051602081830303815290604052906119d85760405162461bcd60e51b81526004016108d291906149be565b5092508260028560028111156119f0576119f0614f64565b14611c31576001600160401b03861615611c21576004805460405163687f4b5760e11b81526001600160401b038916928101929092526000916001600160a01b039091169063d0fe96ae90602401602060405180830381865afa158015611a5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7f9190614fea565b9050611a8b81886128aa565b97508251600014611ab55782898381518110611aa957611aa9615007565b60200260200101819052505b6000636b750d6360e01b89848e8e8e604051602401611ad89594939291906153cd565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b0319909516949094179093526004805482516345d61ded60e01b815292519395506000946001600160a01b03909116936345d61ded9380840193908290030181865afa158015611b53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b779190614fea565b604051631d041f7b60e21b81529091506001600160a01b038216906374107dec90611bad90859087908e90600090600401615491565b600060405180830381600087803b158015611bc757600080fd5b505af1158015611bdb573d6000803e3d6000fd5b505050508a8481518110611bf157611bf1615007565b6020026020010151600960008c81526020019081526020016000209081611c1891906150bc565b50505050611c31565b611c2a8161505d565b9050611881565b505050945094509450949050565b60005460ff16156118505760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b60606000611c92836129dd565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000826000018281548110611cdb57611cdb615007565b9060005260206000200154905092915050565b600060608060005b85811015611d945781878783818110611d1157611d11615007565b9050602002810190611d239190615294565b604051602001611d35939291906154d6565b604051602081830303815290604052915082858281518110611d5957611d59615007565b6020026020010151604051602001611d729291906154fe565b604051602081830303815290604052925080611d8d9061505d565b9050611cf6565b5080516020909101209590945092505050565b600080611db386612a05565b905060007ff6ee28a1d07a7f08b92989953ec3452189f9f998ef0cb91641587f4f9a76c83b8783888888600001358960200135604051602001611dfc979695949392919061552d565b6040516020818303038152906040528051906020012090506000611e55611e2283612a2d565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b9050611e7a81611e6b6060880160408901615586565b87606001358860800135612a5a565b93508460200135421115611ec75760405162461bcd60e51b815260206004820152601460248201527342617365526f757465723a20646561646c696e6560601b60448201526064016108d2565b611ef17f369da55721ba2b3acddd63aac7d6512c3e5762a78fa01c44f423f97868330c3485610bb1565b611f4f5760405162461bcd60e51b815260206004820152602960248201527f42617365526f757465723a20696e76616c6964207369676e617475726520667260448201526837b6903bb7b935b2b960b91b60648201526084016108d2565b505050949350505050565b81341015611fa35760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881a5b9d985b1a5908185b5bdd5b9d60521b60448201526064016108d2565b6000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114611ff0576040519150601f19603f3d011682016040523d82523d6000602084013e611ff5565b606091505b50509050806120465760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a206661696c656420746f2073656e642045746865720000000060448201526064016108d2565b604080516001600160a01b03841681526020810185905233917fbf6afbaffb3b955bebbf43430bbf8eecb8d34ff86f293f592203ab5ed79c5268910160405180910390a2505050565b60606107b36001600160a01b03831660145b606060006120b08360026155a3565b6120bb9060026152fd565b6001600160401b038111156120d2576120d2614a2b565b6040519080825280601f01601f1916602001820160405280156120fc576020820181803683370190505b509050600360fc1b8160008151811061211757612117615007565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061214657612146615007565b60200101906001600160f81b031916908160001a905350600061216a8460026155a3565b6121759060016152fd565b90505b60018111156121ed576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106121a9576121a9615007565b1a60f81b8282815181106121bf576121bf615007565b60200101906001600160f81b031916908160001a90535060049490941c936121e6816155ba565b9050612178565b508315610baa5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016108d2565b600081815260018301602052604081205480156123255760006122606001836152ea565b8554909150600090612274906001906152ea565b90508181146122d957600086600001828154811061229457612294615007565b90600052602060002001549050808760000184815481106122b7576122b7615007565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806122ea576122ea6155d1565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107b3565b60009150506107b3565b604080516060818101835260008083526020830181905292820183905290600061235c8989898989612a84565b92965090945092509050600081600281111561237a5761237a614f64565b0361289e5750604051604160f81b60208201526001908890602101604051602081830303815290604052805190602001200361256c576000868060200190518101906123c691906156b0565b905060006123d7826080015161355f565b90506123f1826020015183604001518460e00151876135da565b6001600160a01b0390811660e08601819052911660408501526020840191909152606083015161242291468c6136ee565b6001600160a01b03166060830152815160408301516020840151612449929190849061380e565b806001600160a01b031663dc64ef4583600001518460200151856060015186608001518760a001518860c001518960e001516040518863ffffffff1660e01b815260040161249d97969594939291906156cd565b6020604051808303816000875af11580156124bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124e0919061570d565b80855260608301516001600160a01b03908116602087015260e084015116604086015260000361256557600b54600160401b900460ff16156125605760405162461bcd60e51b8152602060048201526019602482015278556e6966696564526f7574657256323a20736c69707061676560381b60448201526064016108d2565b600292505b505061289e565b604051602960f91b602082015288906021016040516020818303038152906040528051906020012003612686576000868060200190518101906125af91906156b0565b905060006125c0826080015161355f565b90506125da826020015183604001518460e00151876135da565b6001600160a01b0390811660e08601819052911660408501526020840191909152606083015161260b91468c6136ee565b6001600160a01b03166060830152815160408301516020840151612632929190849061380e565b806001600160a01b031663cd7bfd5883600001518460200151856060015186608001518760a001518860c001518960e001516040518863ffffffff1660e01b815260040161249d97969594939291906156cd565b604051605360f81b60208201528890602101604051602081830303815290604052805190602001200361289a576000868060200190518101906126c99190615726565b905060006126da826080015161355f565b90506126f582602001518360400151846101000151876135da565b6001600160a01b039081166101008601819052911660408501526020840191909152606083015161272791468c6136ee565b6001600160a01b0316606083015281516040830151602084015161274e929190849061380e565b815160208301516060840151608085015160a086015160c087015160e0880151610100890151604051636469c44f60e01b81526001600160a01b039889166004820152602481019790975294871660448701529286166064860152608485019190915260ff90811660a48501521660c4830152821660e482015290821690636469c44f90610104016020604051808303816000875af11580156127f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612819919061570d565b80855260608301516001600160a01b03908116602087015261010084015116604086015260000361256557600b54600160401b900460ff16156125605760405162461bcd60e51b8152602060048201526019602482015278556e6966696564526f7574657256323a20736c69707061676560381b60448201526064016108d2565b5060005b95509550955095915050565b60048054604080516345d61ded60e01b8152905160009384936001600160a01b0316926345d61ded92818301926020928290030181865afa1580156128f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129179190614fea565b90506000816001600160a01b031663d087d2886040518163ffffffff1660e01b8152600401602060405180830381865afa158015612959573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061297d919061570d565b60408051306020808301919091528183018490526001600160401b03881660608301524660808301526001600160a01b03891660a0808401919091528351808403909101815260c090920190925280519101209091505b95945050505050565b600060ff8216601f8111156107b357604051632cd44ac360e21b815260040160405180910390fd5b6001600160a01b03811660009081526008602052604090208054600181018255905b50919050565b60006107b3612a3a61383a565b8360405161190160f01b8152600281019290925260228201526042902090565b6000806000612a6b8787878761396a565b91509150612a7881613a2e565b5090505b949350505050565b604080516060818101835260008083526020830181905292820183905290604051600560fc1b602082015260019088906021016040516020818303038152906040528051906020012003612b9657600086806020019051810190612ae891906157ce565b805160208201516040808401516060850151608086015160a087015160c0880151945163d505accf60e01b81526001600160a01b0396871660048201523060248201526044810194909452606484019290925260ff16608483015260a482015260c4810191909152929350169063d505accf9060e401600060405180830381600087803b158015612b7857600080fd5b505af1158015612b8c573d6000803e3d6000fd5b505050505061289e565b604051614c4d60f01b60208201528890602201604051602081830303815290604052805190602001201480612bf1575060405161425560f01b6020820152889060220160405160208183030381529060405280519060200120145b80612c22575060405161424d60f01b6020820152889060220160405160208183030381529060405280519060200120145b1561319957600086806020019051810190612c3d919061584e565b905089151560000361306c57612c61816020015182604001518360c00151896135da565b6001600160a01b0390811660c0850181905291166040840152602083019190915260608201516080830151612c9792908b6136ee565b6001600160a01b03166060820152604051614c4d60f01b60208201526000908a906022016040516020818303038152906040528051906020012003612ce457612cdf82613b78565b612ea9565b6004805460405163d4f0cceb60e01b81526001600160401b034616928101929092526000916001600160a01b039091169063d4f0cceb90602401602060405180830381865afa158015612d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5f9190614fea565b83516040516305b338c160e21b81526001600160a01b0391821660048201529192508216906316cce30490602401602060405180830381865afa158015612daa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dce9190614fea565b91506001600160a01b03821615612e2857806001600160a01b031683604001516001600160a01b031614612e1457612e1483600001518460400151838660200151613ca2565b6001600160a01b0381166040840152612e2d565b825191505b806001600160a01b031663b6ff156a846000015185602001518660400151876060015188608001516040518663ffffffff1660e01b8152600401612e759594939291906158e5565b600060405180830381600087803b158015612e8f57600080fd5b505af1158015612ea3573d6000803e3d6000fd5b50505050505b8160800151955089604051602001612ec990614c4d60f01b815260020190565b6040516020818303038152906040528051906020012014612fcf576000819050806001600160a01b0316630e7c1cb56040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f4b9190614fea565b6001600160a01b039081168452604080516306ed82dd60e31b815290519183169163376c16e8916004808201926020929091908290030181865afa158015612f97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbb9190615920565b6001600160401b031660a084015250612fdf565b6001600160401b03461660a08301525b81604051602001613055919081516001600160a01b039081168252602080840151908301526040808401518216908301526060808401518216908301526080808401516001600160401b039081169184019190915260a0848101519091169083015260c092830151169181019190915260e00190565b604051602081830303815290604052945050613193565b600a546000908152600d602052604081205460ff16600281111561309257613092614f64565b146130d65760405162461bcd60e51b8152602060048201526014602482015273149bdd5d195c8e881bdc081c1c9bd8d95cdcd95960621b60448201526064016108d2565b600a546000908152600d60205260409020805460ff1916600117905560608101516001600160a01b031661312b5761311c81606001518260c0015183608001518b6136ee565b6001600160a01b031660608201525b60405161425560f01b6020820152899060220160405160208183030381529060405280519060200120146131675761316281613d0d565b613170565b61317081613e14565b835260608101516001600160a01b03908116602085015260c08201511660408401525b5061289e565b604051605760f81b602082015288906021016040516020818303038152906040528051906020012014806131f3575060405161557760f01b6020820152889060220160405160208183030381529060405280519060200120145b156132ce5760008680602001905181019061320e919061593d565b905060006132278260200151836040015160008a6135da565b6001600160a01b039091166040850152602084019190915260608301519091506132539080468c6136ee565b6001600160a01b03166060830152604051605760f81b60208201528a90602101604051602081830303815290604052805190602001201461329c5761329782613ed2565b6132a5565b6132a58261401d565b845250606001516001600160a01b0390811660208401526040868101519091169083015261289e565b60405161214d60f01b60208201528890602201604051602081830303815290604052805190602001201480613329575060405161215560f01b6020820152889060220160405160208183030381529060405280519060200120145b1561354d5760008680602001905181019061334491906159b8565b90508915156000036133e357600181516000908152600d602052604090205460ff16600281111561337757613377614f64565b036133bb5760405162461bcd60e51b8152602060048201526014602482015273149bdd5d195c8e881bdc081c1c9bd8d95cdcd95960621b60448201526064016108d2565b80516000908152600d60209081526040909120805460ff191660021790558101519450613193565b8051600090815260096020526040812080546133fe90614fab565b80601f016020809104026020016040519081016040528092919081815260200182805461342a90614fab565b80156134775780601f1061344c57610100808354040283529160200191613477565b820191906000526020600020905b81548152906001019060200180831161345a57829003601f168201915b5050505050905080516000036134c85760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881bdc081b9bdd081cdd185c9d195960521b60448201526064016108d2565b6000818060200190518101906134de919061584e565b835160009081526009602052604081209192506134fb9190614872565b60405161214d60f01b60208201528b90602201604051602081830303815290604052805190602001200361353957613532816140e7565b8552613545565b6135428161420a565b85525b50505061289e565b50839050600095509550955095915050565b6001600160a01b038082166000908152600e602052604090205416806135d55760405162461bcd60e51b815260206004820152602560248201527f556e6966696564526f7574657256323a20706f6f6c2061646170746572206e6f6044820152641d081cd95d60da1b60648201526084016108d2565b919050565b600080600060001987146135ee57866135f1565b83515b92506001600160a01b03861615613659576001600160a01b03861633146136515760405162461bcd60e51b81526020600482015260146024820152732937baba32b91d103bb937b7339039b2b73232b960611b60448201526064016108d2565b859150613661565b836020015191505b600a5415801561367957506001600160a01b03851615155b156136dd576001600160a01b03851633146136d65760405162461bcd60e51b815260206004820152601960248201527f526f757465723a2077726f6e6720656d657267656e6379546f0000000000000060448201526064016108d2565b50836136e4565b5060408301515b9450945094915050565b60006136fc858585856143b4565b90506001600160a01b038116612a7c57604051604160f81b6020820152602101604051602081830303815290604052805190602001208214806137635750604051602960f91b60208201526021016040516020818303038152906040528051906020012082145b806137925750604051605360f81b60208201526021016040516020818303038152906040528051906020012082145b15612a7c576004805460405163687f4b5760e11b81526001600160401b038616928101929092526001600160a01b03169063d0fe96ae906024015b602060405180830381865afa1580156137ea573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129d49190614fea565b306001600160a01b0384160361382e5761382984838361464a565b610d63565b610d6384848484613ca2565b6000306001600160a01b037f000000000000000000000000fa43de785dd3cd0ef3dae0dd2b8be3f1b5112d1a1614801561389357507f000000000000000000000000000000000000000000000000000000000000008946145b156138bd57507f185098b39f78ee4b461c4ac02ccb269062eb3e908652ed1205d11f877dfdb58990565b613965604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527fc2a59fd4499513f5d074d325c5dcf8b1f005e4fbb0493c56f92b05b38e5d3b25918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156139a15750600090506003613a25565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156139f5573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613a1e57600060019250925050613a25565b9150600090505b94509492505050565b6000816004811115613a4257613a42614f64565b03613a4a5750565b6001816004811115613a5e57613a5e614f64565b03613aab5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016108d2565b6002816004811115613abf57613abf614f64565b03613b0c5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016108d2565b6003816004811115613b2057613b20614f64565b036108f85760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016108d2565b60048054604051630f5427af60e41b81526001600160401b034616928101929092526000916001600160a01b039091169063f5427af090602401602060405180830381865afa158015613bcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bf39190614fea565b9050806001600160a01b031682604001516001600160a01b031614613c2a57613c2a82600001518360400151838560200151613ca2565b806001600160a01b0316633fea56b883600001518460200151856040015186606001516040518563ffffffff1660e01b8152600401613c6c9493929190615a0d565b600060405180830381600087803b158015613c8657600080fd5b505af1158015613c9a573d6000803e3d6000fd5b505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052610d639085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261467a565b6004805460405163d4f0cceb60e01b81526001600160401b0346169281019290925260009182916001600160a01b03169063d4f0cceb90602401602060405180830381865afa158015613d64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d889190614fea565b83516020850151604080870151606088015160a0890151925163df543e8160e01b81529596506001600160a01b0387169563df543e8195613dd1959094909392916004016158e5565b6020604051808303816000875af1158015613df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610baa919061570d565b60048054604051630f5427af60e41b81526001600160401b0346169281019290925260009182916001600160a01b03169063f5427af090602401602060405180830381865afa158015613e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e8f9190614fea565b8351602085015160408087015160608801519151637f27a5b960e11b81529495506001600160a01b0386169463fe4f4b7294613dd1949093909291600401615a0d565b60408101516000906001600160a01b03163014613f0157613f0182600001518360400151308560200151613ca2565b81516020830151604051632e1a7d4d60e01b81526001600160a01b0390921691632e1a7d4d91613f379160040190815260200190565b600060405180830381600087803b158015613f5157600080fd5b505af1158015613f65573d6000803e3d6000fd5b50505050600082606001516001600160a01b0316836020015160405160006040518083038185875af1925050503d8060008114613fbe576040519150601f19603f3d011682016040523d82523d6000602084013e613fc3565b606091505b50509050806140145760405162461bcd60e51b815260206004820152601a60248201527f526f757465723a206661696c656420746f2073656e642045544800000000000060448201526064016108d2565b50506020015190565b6000816020015134101561406c5760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881a5b9d985b1a5908185b5bdd5b9d60521b60448201526064016108d2565b81600001516001600160a01b031663d0e30db083602001516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156140af57600080fd5b505af11580156140c3573d6000803e3d6000fd5b50505050506140df82600001518360600151846020015161464a565b506020015190565b6080810151600b546000916001600160401b0391821691161461414c5760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a2077726f6e6720656d657267656e637920696e69740000000060448201526064016108d2565b60048054604051630f5427af60e41b81526001600160401b034616928101929092526000916001600160a01b039091169063f5427af090602401602060405180830381865afa1580156141a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c79190614fea565b8351602085015160408087015160c0880151915163c26b5bab60e01b81529495506001600160a01b0386169463c26b5bab94613dd1949093909291600401615a0d565b6080810151600b546000916001600160401b0391821691161461426f5760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a2077726f6e6720656d657267656e637920696e69740000000060448201526064016108d2565b6004805460405163d4f0cceb60e01b81526001600160401b034616928101929092526000916001600160a01b039091169063d4f0cceb90602401602060405180830381865afa1580156142c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142ea9190614fea565b60a08401518451604051637f9fa89f60e01b81526001600160401b0390921660048301526001600160a01b03908116602483015291925090821690637f9fa89f90604401602060405180830381865afa15801561434b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061436f9190614fea565b6001600160a01b03908116808552602085015160408087015160c0880151915163550bf7db60e11b81529486169463aa17efb694613dd1949093909291600401615a0d565b60006001600160a01b03851615806143ca575081155b6144095760405162461bcd60e51b815260206004820152601060248201526f526f757465723a2077726f6e6720746f60801b60448201526064016108d2565b8161447057849050836001600160a01b0316816001600160a01b03161461446b5760405162461bcd60e51b81526020600482015260166024820152752937baba32b91d103bb937b733903932b1b2b4bb32b960511b60448201526064016108d2565b612a7c565b604051614c4d60f01b602082015260220160405160208183030381529060405280519060200120820361451b5760048054604051630f5427af60e41b81526001600160401b038616928101929092526001600160a01b03169063f5427af0906024015b602060405180830381865afa1580156144f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145149190614fea565b9050612a7c565b60405161425560f01b602082015260220160405160208183030381529060405280519060200120821480614574575060405161424d60f01b60208201526022016040516020818303038152906040528051906020012082145b156145b3576004805460405163d4f0cceb60e01b81526001600160401b038616928101929092526001600160a01b03169063d4f0cceb906024016144d3565b604051605760f81b60208201528290602101604051602081830303815290604052805190602001201480613792575060405161557760f01b602082015282906022016040516020818303038152906040528051906020012003612a7c576004805460405163687f4b5760e11b81526001600160401b038616928101929092526001600160a01b03169063d0fe96ae906024016137cd565b6040516001600160a01b03831660248201526044810182905261086190849063a9059cbb60e01b90606401613cd6565b60006146cf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661474f9092919063ffffffff16565b90508051600014806146f05750808060200190518101906146f09190615a38565b6108615760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016108d2565b6060612a7c848460008585600080866001600160a01b031685876040516147769190615a55565b60006040518083038185875af1925050503d80600081146147b3576040519150601f19603f3d011682016040523d82523d6000602084013e6147b8565b606091505b50915091506147c9878383876147d4565b979650505050505050565b6060831561484357825160000361483c576001600160a01b0385163b61483c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108d2565b5081612a7c565b612a7c83838151156148585781518083602001fd5b8060405162461bcd60e51b81526004016108d291906149be565b50805461487e90614fab565b6000825580601f1061488e575050565b601f0160209004906000526020600020908101906108f891905b808211156148bc57600081556001016148a8565b5090565b80356001600160e01b0319811681146135d557600080fd5b6000602082840312156148ea57600080fd5b610baa826148c0565b6001600160a01b03811681146108f857600080fd5b60006020828403121561491a57600080fd5b8135610baa816148f3565b60006020828403121561493757600080fd5b5035919050565b6000806040838503121561495157600080fd5b823591506020830135614963816148f3565b809150509250929050565b60005b83811015614989578181015183820152602001614971565b50506000910152565b600081518084526149aa81602086016020860161496e565b601f01601f19169290920160200192915050565b602081526000610baa6020830184614992565b60ff811681146108f857600080fd5b60008083601f8401126149f257600080fd5b5081356001600160401b03811115614a0957600080fd5b6020830191508360208260051b8501011115614a2457600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715614a6357614a63614a2b565b60405290565b60405161012081016001600160401b0381118282101715614a6357614a63614a2b565b60405160e081016001600160401b0381118282101715614a6357614a63614a2b565b604051601f8201601f191681016001600160401b0381118282101715614ad657614ad6614a2b565b604052919050565b60006001600160401b03821115614af757614af7614a2b565b5060051b60200190565b60006001600160401b03831115614b1a57614b1a614a2b565b614b2d601f8401601f1916602001614aae565b9050828152838383011115614b4157600080fd5b828260208301376000602084830101529392505050565b600082601f830112614b6957600080fd5b81356020614b7e614b7983614ade565b614aae565b82815260059290921b84018101918181019086841115614b9d57600080fd5b8286015b84811015614bf15780356001600160401b03811115614bc05760008081fd5b8701603f81018913614bd25760008081fd5b614be3898683013560408401614b01565b845250918301918301614ba1565b509695505050505050565b600080600080600060808688031215614c1457600080fd5b853594506020860135614c26816149d1565b935060408601356001600160401b0380821115614c4257600080fd5b614c4e89838a016149e0565b90955093506060880135915080821115614c6757600080fd5b50614c7488828901614b58565b9150509295509295909350565b60ff60f81b881681526000602060e081840152614ca160e084018a614992565b8381036040850152614cb3818a614992565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015614d0557835183529284019291840191600101614ce9565b50909c9b505050505050505050505050565b60008060408385031215614d2a57600080fd5b50508035926020909101359150565b80151581146108f857600080fd5b60006020808385031215614d5a57600080fd5b82356001600160401b0380821115614d7157600080fd5b818501915085601f830112614d8557600080fd5b8135614d93614b7982614ade565b81815260059190911b83018401908481019088831115614db257600080fd5b8585015b83811015614e4857803585811115614dce5760008081fd5b86016040818c03601f1901811315614de65760008081fd5b614dee614a41565b8983013588811115614e005760008081fd5b8301603f81018e13614e125760008081fd5b614e228e8c830135858401614b01565b8252509181013591614e3383614d39565b808a0192909252508352918601918601614db6565b5098975050505050505050565b6001600160401b03811681146108f857600080fd5b600080600060608486031215614e7f57600080fd5b614e88846148c0565b92506020840135614e98816148f3565b91506040840135614ea881614e55565b809150509250925092565b60008060008084860360e0811215614eca57600080fd5b85356001600160401b0380821115614ee157600080fd5b614eed89838a016149e0565b90975095506020880135915080821115614f0657600080fd5b50614f1388828901614b58565b93505060a0603f1982011215614f2857600080fd5b509295919450926040019150565b60008060408385031215614f4957600080fd5b8235614f54816148f3565b91506020830135614963816148f3565b634e487b7160e01b600052602160045260246000fd5b600381106108f857634e487b7160e01b600052602160045260246000fd5b60208101614fa583614f7a565b91905290565b600181811c90821680614fbf57607f821691505b602082108103612a2757634e487b7160e01b600052602260045260246000fd5b80516135d5816148f3565b600060208284031215614ffc57600080fd5b8151610baa816148f3565b634e487b7160e01b600052603260045260246000fd5b6060815260006150306060830186614992565b602083019490945250901515604090910152919050565b634e487b7160e01b600052601160045260246000fd5b60006001820161506f5761506f615047565b5060010190565b601f82111561086157600081815260208120601f850160051c8101602086101561509d5750805b601f850160051c820191505b81811015613c9a578281556001016150a9565b81516001600160401b038111156150d5576150d5614a2b565b6150e9816150e38454614fab565b84615076565b602080601f83116001811461511e57600084156151065750858301515b600019600386901b1c1916600185901b178555613c9a565b600085815260208120601f198616915b8281101561514d5788860151825594840194600190910190840161512e565b508582101561516b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60208082526018908201527f42617365526f757465723a2077726f6e6720706172616d730000000000000000604082015260600190565b6001600160401b03878116825260208201879052851660408201526060810184905260c081016151e184614f7a565b83608083015260ff831660a0830152979650505050505050565b80516020808301519190811015612a275760001960209190910360031b1b16919050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161525781601785016020880161496e565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161528881602884016020880161496e565b01602801949350505050565b6000808335601e198436030181126152ab57600080fd5b8301803591506001600160401b038211156152c557600080fd5b602001915036819003821315614a2457600080fd5b8183823760009101908152919050565b818103818111156107b3576107b3615047565b808201808211156107b3576107b3615047565b6a02937baba32b91d1037b8160ad1b81528183600b83013770081a5cc81b9bdd081cdd5c1c1bdc9d1959607a1b9101600b810191909152601c01919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526020808501808196508360051b8101915082860160005b858110156153c05782840389526153ae848351614992565b98850198935090840190600101615396565b5091979650505050505050565b600060808201878352602060ff881681850152608060408501528186835260a08501905060a08760051b86010192508760005b8881101561546f57868503609f190183528135368b9003601e1901811261542657600080fd5b8a0184810190356001600160401b0381111561544157600080fd5b80360382131561545057600080fd5b61545b87828461534f565b965050509183019190830190600101615400565b5050505082810360608401526154858185615378565b98975050505050505050565b6080815260006154a46080830187614992565b6001600160a01b0395861660208401526001600160401b03949094166040830152509216606090920191909152919050565b600084516154e881846020890161496e565b8201838582376000930192835250909392505050565b6000835161551081846020880161496e565b83519083019061552481836020880161496e565b01949350505050565b8781526bffffffffffffffffffffffff198760601b1660208201528560348201528460548201526000845161556981607485016020890161496e565b909101607481019390935250609482015260b40195945050505050565b60006020828403121561559857600080fd5b8135610baa816149d1565b80820281158282048414176107b3576107b3615047565b6000816155c9576155c9615047565b506000190190565b634e487b7160e01b600052603160045260246000fd5b80516135d5816149d1565b600061010080838503121561560657600080fd5b604051908101906001600160401b038211818310171561562857615628614a2b565b816040528092508351915061563c826148f3565b8181526020840151602082015261565560408501614fdf565b604082015261566660608501614fdf565b606082015261567760808501614fdf565b608082015260a084015160a082015261569260c085016155e7565b60c08201526156a360e08501614fdf565b60e0820152505092915050565b600061010082840312156156c357600080fd5b610baa83836155f2565b6001600160a01b039788168152602081019690965293861660408601529185166060850152608084015260ff1660a083015290911660c082015260e00190565b60006020828403121561571f57600080fd5b5051919050565b6000610120828403121561573957600080fd5b615741614a69565b61574a83614fdf565b81526020830151602082015261576260408401614fdf565b604082015261577360608401614fdf565b606082015261578460808401614fdf565b608082015260a083015160a082015261579f60c084016155e7565b60c08201526157b060e084016155e7565b60e08201526101006157c3818501614fdf565b908201529392505050565b600060e082840312156157e057600080fd5b6157e8614a8c565b82516157f3816148f3565b81526020830151615803816148f3565b806020830152506040830151604082015260608301516060820152608083015161582c816149d1565b608082015260a0838101519082015260c0928301519281019290925250919050565b600060e0828403121561586057600080fd5b615868614a8c565b8251615873816148f3565b815260208381015190820152604083015161588d816148f3565b604082015260608301516158a0816148f3565b606082015260808301516158b381614e55565b608082015260a08301516158c681614e55565b60a082015260c08301516158d9816148f3565b60c08201529392505050565b6001600160a01b0395861681526020810194909452918416604084015290921660608201526001600160401b03909116608082015260a00190565b60006020828403121561593257600080fd5b8151610baa81614e55565b60006080828403121561594f57600080fd5b604051608081018181106001600160401b038211171561597157615971614a2b565b604052825161597f816148f3565b8152602083810151908201526040830151615999816148f3565b604082015260608301516159ac816148f3565b60608201529392505050565b6000604082840312156159ca57600080fd5b604051604081018181106001600160401b03821117156159ec576159ec614a2b565b604052825181526020830151615a0181614e55565b60208201529392505050565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b600060208284031215615a4a57600080fd5b8151610baa81614d39565b60008251615a6781846020870161496e565b919091019291505056fea2646970667358221220536cace6d8a04a3954633ca623643535b8a2560e5c4e4682ca9ccaa70fd0f0ff64736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000564a0c04877e4ca6f5d0cad8c20522226321d9b0
-----Decoded View---------------
Arg [0] : addressBook_ (address): 0x564A0c04877E4ca6f5d0CAd8C20522226321d9b0
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000564a0c04877e4ca6f5d0cad8c20522226321d9b0
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.