More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 21,854 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Start | 99556257 | 1 min ago | IN | 0.01790266 FTM | 0.00175904 | ||||
Start | 99556138 | 3 mins ago | IN | 0.00486694 FTM | 0.00177434 | ||||
Start | 99555770 | 9 mins ago | IN | 0.01767552 FTM | 0.00162586 | ||||
Start | 99555648 | 11 mins ago | IN | 0.00486967 FTM | 0.00163259 | ||||
Start | 99555519 | 13 mins ago | IN | 0.01790431 FTM | 0.0015465 | ||||
Start | 99555257 | 17 mins ago | IN | 0.01877701 FTM | 0.00181942 | ||||
Start | 99555130 | 19 mins ago | IN | 0.00490734 FTM | 0.00227417 | ||||
Start | 99555002 | 22 mins ago | IN | 0.0183541 FTM | 0.00153221 | ||||
Start | 99554747 | 26 mins ago | IN | 0.0187262 FTM | 0.00150176 | ||||
Start | 99554600 | 28 mins ago | IN | 0.00487179 FTM | 0.00150125 | ||||
Start | 99554479 | 30 mins ago | IN | 0.0182685 FTM | 0.00149346 | ||||
Start | 99554203 | 34 mins ago | IN | 0.0184196 FTM | 0.00153003 | ||||
Start | 99554065 | 37 mins ago | IN | 0.00492984 FTM | 0.00170955 | ||||
Start | 99553989 | 38 mins ago | IN | 0.04588849 FTM | 0.00585057 | ||||
Start | 99553930 | 39 mins ago | IN | 0.01816818 FTM | 0.00152575 | ||||
Start | 99553662 | 43 mins ago | IN | 0.01860793 FTM | 0.00152724 | ||||
Start | 99553542 | 45 mins ago | IN | 0.01816515 FTM | 0.00362155 | ||||
Start | 99553527 | 45 mins ago | IN | 0.00495581 FTM | 0.00153168 | ||||
Start | 99553416 | 47 mins ago | IN | 0.0175963 FTM | 0.00154591 | ||||
Start | 99553151 | 51 mins ago | IN | 0.01665928 FTM | 0.00150969 | ||||
Start | 99553020 | 53 mins ago | IN | 0.00493871 FTM | 0.00150826 | ||||
Start | 99552890 | 55 mins ago | IN | 0.01779295 FTM | 0.00152831 | ||||
Start | 99552648 | 1 hr ago | IN | 0.01668911 FTM | 0.0014491 | ||||
Start | 99552508 | 1 hr ago | IN | 0.0047082 FTM | 0.00144559 | ||||
Start | 99552470 | 1 hr ago | IN | 0.00082274 FTM | 0.00468025 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
99556257 | 1 min ago | 0.01790266 FTM | ||||
99556138 | 3 mins ago | 0.00486694 FTM | ||||
99555770 | 9 mins ago | 0.01767552 FTM | ||||
99555648 | 11 mins ago | 0.00486967 FTM | ||||
99555519 | 13 mins ago | 0.01790431 FTM | ||||
99555257 | 17 mins ago | 0.01877701 FTM | ||||
99555130 | 19 mins ago | 0.00490734 FTM | ||||
99555002 | 22 mins ago | 0.0183541 FTM | ||||
99554747 | 26 mins ago | 0.0187262 FTM | ||||
99554600 | 28 mins ago | 0.00487179 FTM | ||||
99554479 | 30 mins ago | 0.0182685 FTM | ||||
99554203 | 34 mins ago | 0.0184196 FTM | ||||
99554065 | 37 mins ago | 0.00492984 FTM | ||||
99553989 | 38 mins ago | 0.04588849 FTM | ||||
99553930 | 39 mins ago | 0.01816818 FTM | ||||
99553662 | 43 mins ago | 0.01860793 FTM | ||||
99553542 | 45 mins ago | 0.01816515 FTM | ||||
99553527 | 45 mins ago | 0.00495581 FTM | ||||
99553416 | 47 mins ago | 0.0175963 FTM | ||||
99553151 | 51 mins ago | 0.01665928 FTM | ||||
99553020 | 53 mins ago | 0.00493871 FTM | ||||
99552890 | 55 mins ago | 0.01779295 FTM | ||||
99552648 | 1 hr ago | 0.01668911 FTM | ||||
99552508 | 1 hr ago | 0.0047082 FTM | ||||
99552470 | 1 hr ago | 0.00082274 FTM |
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_; emit PoolAdapterSet(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.4) (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. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ 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]. * * CAUTION: See Security Considerations above. */ 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 (last updated v4.9.4) (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; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// 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 "./interfaces/IOpsRegistrar.sol"; import "./utils/RequestIdLib.sol"; abstract contract BaseRouter is Pausable, EIP712, EndPoint, AccessControlEnumerable { using Counters for Counters.Counter; enum ExecutionResult { Failed, Succeeded, Interrupted } 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 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 current ops index uint256 internal currentOpsIdx; /// @dev current ops count uint256 internal currentOpsCount; /// @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 ); 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 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"); uint256 balanceBeforeStart = address(this).balance - msg.value; address opsRegistrar = IAddressBook(addressBook).opsRegistrar(); { (bytes32 hash, bytes memory data) = _getRawData(operations, params); require(IOpsRegistrar(opsRegistrar).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); uint256 newBalance = address(this).balance; if(newBalance > balanceBeforeStart) { (bool sent, ) = msg.sender.call{value: newBalance - balanceBeforeStart}(""); require(sent, "BaseRouter: failed to send ETH"); } 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; currentOpsCount = operations.length; for (uint256 i = cPos; i < operations.length; ++i) { currentOpsIdx = 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; } } currentOpsIdx = 0; currentOpsCount = 0; } /** * @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])); if (data.length == 0) { data = params[i]; } else { 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-2024 - 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); /// @dev returns opsRegistrar function opsRegistrar() external view returns (address); /// @dev returns wrapped native asset (WETH) function WETH() 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 IOpsRegistrar { struct ComplexOp { string operation; bool registered; } /// @dev returns is complex op registered function ops(bytes32 ops_) external returns (bool); /// @dev registers ComplexOp's function registerComplexOp(ComplexOp[] memory complexOps_) external; }
// 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 { }
// 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; interface IWhitelist { enum TokenState { NotSet, InOut } enum PoolState { NotSet, AddSwapRemove } struct TokenStatus { address token; uint256 min; uint256 max; uint256 bridgeFee; TokenState state; } struct PoolStatus { address pool; uint256 aggregationFee; PoolState state; } function tokenMin(address token) external view returns (uint256); function tokenMax(address token) external view returns (uint256); function tokenMinMax(address token) external view returns (uint256, uint256); function bridgeFee(address token) external view returns (uint256); function tokenState(address token) external view returns (uint8); function tokenStatus(address token) external view returns (TokenStatus memory); function tokens(uint256 offset, uint256 count) external view returns (TokenStatus[] memory); function aggregationFee(address pool) external view returns (uint256); function poolState(address pool) external view returns (uint8); function poolStatus(address pool) external view returns (PoolStatus memory); function pools(uint256 offset, uint256 count) external view returns (PoolStatus[] memory); }
// 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"; import "./interfaces/IWhitelist.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; /// @dev WETH address address public WETH; modifier onlyBridge() { address bridge = IAddressBook(addressBook).bridge(); require(bridge == msg.sender, "Router: bridge only"); _; } constructor(address addressBook_) BaseRouter(addressBook_) { WETH = IAddressBook(addressBook).WETH(); require(WETH != address(0), "Router: WETH incorrect"); } receive() external payable { require(msg.sender == WETH, "Router: Invalid sender"); } 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 nonReentrant originNetwork { _start(operations, params, receipt); } function resume( bytes32 requestId, uint8 cPos, string[] calldata operations, bytes[] memory params ) external nonReentrant onlyBridge crosschainHandling(requestId) { _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) { require(currentOpsIdx == 0, "Router: permit not allowed"); PermitParams memory p = abi.decode(params, (PermitParams)); try IERC20WithPermit(p.token).permit( p.owner, address(this), p.amount, p.deadline, p.v, p.r, p.s ) { } catch { require(IERC20(p.token).allowance(p.owner, address(this)) >= p.amount, "Router: permit failure"); } } 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 { // check for backward compatibility with deployed SynthesisV2 IAddressBook addressBookImpl = IAddressBook(addressBook); address whitelist = addressBookImpl.whitelist(); require(IWhitelist(whitelist).tokenState(p.tokenIn) >= 0, "Router: synth must be whitelisted"); 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(currentOpsIdx == 0, "Router: wrap not allowed"); 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) { require(currentOpsIdx == (currentOpsCount - 1), "Router: unwrap not allowed"); 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 { if (executionPrice != 0) { 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
[{"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":[],"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":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[],"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":[{"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
6101606040523480156200001257600080fd5b5060405162006472380380620064728339810160408190526200003591620004e0565b60408051808201825260048152634559574160e01b60208083019190915282518084019093526001808452603160f81b848301526000805460ff191690558493849384939092620000929184919062000fd962000297821b17901c565b61012052620000af81600262000297602090811b62000fd917901c565b61014052815160208084019190912060e052815190820120610100524660a0526200013d60e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052604080518082019091526005815264322e322e3360d81b6020820152600390620001719082620005af565b506200017d81620002e7565b600480546001600160a01b0319166001600160a01b0392909216919091179055620001aa60003362000342565b506001600e5560048054604080516315ab88c960e31b815290516001600160a01b039092169263ad5c46489282820192602092908290030181865afa158015620001f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200021e9190620004e0565b601080546001600160a01b0319166001600160a01b039290921691821790556200028f5760405162461bcd60e51b815260206004820152601660248201527f526f757465723a205745544820696e636f72726563740000000000000000000060448201526064015b60405180910390fd5b5050620006f0565b6000602083511015620002b757620002af8362000385565b9050620002e1565b82620002ce83620003c860201b620003131760201c565b90620002db9082620005af565b5060ff90505b92915050565b6001600160a01b0381166200033f5760405162461bcd60e51b815260206004820152601660248201527f456e64506f696e743a207a65726f206164647265737300000000000000000000604482015260640162000286565b50565b620003598282620003cb60201b6200100a1760201c565b6000828152600660209081526040909120620003809183906200109062000470821b17901c565b505050565b600080829050601f81511115620003b3578260405163305a27a960e01b81526004016200028691906200067b565b8051620003c082620006cb565b179392505050565b90565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff166200046c5760008281526005602090815260408083206001600160a01b03851684529091529020805460ff191660011790556200042b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b600062000487836001600160a01b0384166200048e565b9392505050565b6000818152600183016020526040812054620004d757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620002e1565b506000620002e1565b600060208284031215620004f357600080fd5b81516001600160a01b03811681146200048757600080fd5b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200053657607f821691505b6020821081036200055757634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200038057600081815260208120601f850160051c81016020861015620005865750805b601f850160051c820191505b81811015620005a75782815560010162000592565b505050505050565b81516001600160401b03811115620005cb57620005cb6200050b565b620005e381620005dc845462000521565b846200055d565b602080601f8311600181146200061b5760008415620006025750858301515b600019600386901b1c1916600185901b178555620005a7565b600085815260208120601f198616915b828110156200064c578886015182559484019460019091019084016200062b565b50858210156200066b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208083528351808285015260005b81811015620006aa578581018301518582016040015282016200068c565b506000604082860101526040601f19601f8301168501019250505092915050565b80516020808301519190811015620005575760001960209190910360031b1b16919050565b60805160a05160c05160e051610100516101205161014051615d276200074b6000396000610b5801526000610b2d01526000613c4701526000613c1f01526000613b7a01526000613ba401526000613bce0152615d276000f3fe60806040526004361061023f5760003560e01c806384b0196e1161012e578063ad5c4648116100ab578063ca15c8731161006f578063ca15c873146106d8578063d547741f146106f8578063f5887cdd14610718578063f5b541a614610738578063f87cf42b1461076c57600080fd5b8063ad5c464814610650578063b4ccca0d14610670578063ba677db714610690578063bcf4f0a6146106a3578063beadbe32146106c357600080fd5b80639bb68c75116100f25780639bb68c75146105bd578063a217fddf146105d2578063a785ac5a146105e7578063ab1efbab14610607578063ad351f9f1461063b57600080fd5b806384b0196e1461050a5780639010d07c1461053257806391d148541461055257806395ad709a146105725780639ba520ad146105a857600080fd5b80633e7e25c1116101bc5780636b750d63116101805780636b750d631461048b57806376a3fb3e146104ab578063778c89b9146104c05780637ecebe00146104d55780638456cb59146104f557600080fd5b80633e7e25c1146104005780633f4ba83a1461042757806354fd4d501461043c5780635c975abb1461045e5780636869cb961461047657600080fd5b80632b385bcf116102035780632b385bcf146103815780632d07ae69146103965780632ee63e44146103ab5780632f2ff15d146103c057806336568abe146103e057600080fd5b806301ffc9a7146102a35780630b3448a8146102d85780630e03e490146102f85780630ff53ba71461032e578063248a9ca31461035157600080fd5b3661029e576010546001600160a01b0316331461029c5760405162461bcd60e51b81526020600482015260166024820152752937baba32b91d1024b73b30b634b21039b2b73232b960511b60448201526064015b60405180910390fd5b005b600080fd5b3480156102af57600080fd5b506102c36102be366004614cbb565b6107a9565b60405190151581526020015b60405180910390f35b3480156102e457600080fd5b5061029c6102f3366004614ceb565b6107d4565b34801561030457600080fd5b50610316610313366004614d08565b90565b6040516001600160a01b0390911681526020016102cf565b34801561033a57600080fd5b506103436107ec565b6040519081526020016102cf565b34801561035d57600080fd5b5061034361036c366004614d08565b60009081526005602052604090206001015490565b34801561038d57600080fd5b50610343610817565b3480156103a257600080fd5b5061034361082c565b3480156103b757600080fd5b50610343610841565b3480156103cc57600080fd5b5061029c6103db366004614d21565b610857565b3480156103ec57600080fd5b5061029c6103fb366004614d21565b610881565b34801561040c57600080fd5b5061034361041b366004614ceb565b6001600160a01b031690565b34801561043357600080fd5b5061029c6108fb565b34801561044857600080fd5b50610451610911565b6040516102cf9190614da1565b34801561046a57600080fd5b5060005460ff166102c3565b34801561048257600080fd5b5061034361099f565b34801561049757600080fd5b5061029c6104a6366004614f93565b6109b5565b3480156104b757600080fd5b50610343610ac2565b3480156104cc57600080fd5b50610343610ad8565b3480156104e157600080fd5b506103436104f0366004614ceb565b610aee565b34801561050157600080fd5b5061029c610b0c565b34801561051657600080fd5b5061051f610b1f565b6040516102cf9796959493929190615018565b34801561053e57600080fd5b5061031661054d3660046150ae565b610ba8565b34801561055e57600080fd5b506102c361056d366004614d21565b610bc7565b34801561057e57600080fd5b5061031661058d366004614ceb565b6011602052600090815260409020546001600160a01b031681565b3480156105b457600080fd5b50610343610bf2565b3480156105c957600080fd5b50610343610c07565b3480156105de57600080fd5b50610343600081565b3480156105f357600080fd5b50610451610602366004614d08565b610c1d565b34801561061357600080fd5b506103437f369da55721ba2b3acddd63aac7d6512c3e5762a78fa01c44f423f97868330c3481565b34801561064757600080fd5b50610343610c36565b34801561065c57600080fd5b50601054610316906001600160a01b031681565b34801561067c57600080fd5b506102c361068b3660046150e5565b610c4b565b61029c61069e36600461512e565b610e61565b3480156106af57600080fd5b5061029c6106be3660046151b1565b610e9c565b3480156106cf57600080fd5b50610343610f88565b3480156106e457600080fd5b506103436106f3366004614d08565b610f9d565b34801561070457600080fd5b5061029c610713366004614d21565b610fb4565b34801561072457600080fd5b50600454610316906001600160a01b031681565b34801561074457600080fd5b506103437f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b34801561077857600080fd5b5061079c610787366004614d08565b600f6020526000908152604090205460ff1681565b6040516102cf9190615213565b60006001600160e01b03198216635a05180f60e01b14806107ce57506107ce826110a5565b92915050565b60006107df816110da565b6107e8826110e4565b5050565b60405161215560f01b60208201526022015b6040516020818303038152906040528051906020012081565b604051605760f81b60208201526021016107fe565b604051602960f91b60208201526021016107fe565b604051614c4d60f01b60208201526022016107fe565b600082815260056020526040902060010154610872816110da565b61087c838361110f565b505050565b6001600160a01b03811633146108f15760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610293565b6107e88282611131565b6000610906816110da565b61090e611153565b50565b6003805461091e90615226565b80601f016020809104026020016040519081016040528092919081815260200182805461094a90615226565b80156109975780601f1061096c57610100808354040283529160200191610997565b820191906000526020600020905b81548152906001019060200180831161097a57829003601f168201915b505050505081565b60405161424d60f01b60208201526022016107fe565b6109bd6111a5565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e78cea926040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a369190615265565b90506001600160a01b0381163314610a865760405162461bcd60e51b8152602060048201526013602482015272526f757465723a20627269646765206f6e6c7960681b6044820152606401610293565b600986905585610a9981878787876111fe565b50506000600955600a805467ffffffffffffffff19169055610abb6001600e55565b5050505050565b60405161425560f01b60208201526022016107fe565b60405161557760f01b60208201526022016107fe565b6001600160a01b0381166000908152600760205260408120546107ce565b6000610b17816110da565b61090e6112fb565b600060608082808083610b537f00000000000000000000000000000000000000000000000000000000000000006001611338565b610b7e7f00000000000000000000000000000000000000000000000000000000000000006002611338565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6000828152600660205260408120610bc090836113dc565b9392505050565b60009182526005602090815260408084206001600160a01b0393909316845291905290205460ff1690565b604051604160f81b60208201526021016107fe565b60405161214d60f01b60208201526022016107fe565b6008602052600090815260409020805461091e90615226565b604051600560fc1b60208201526021016107fe565b60048054604080516373c6754960e11b8152905160009384936001600160a01b03169263e78cea9292818301926020928290030181865afa158015610c94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb89190615265565b90506001600160a01b0381163314610d085760405162461bcd60e51b8152602060048201526013602482015272526f757465723a20627269646765206f6e6c7960681b6044820152606401610293565b6004805460405163687f4b5760e11b81526001600160401b038616928101929092526000916001600160a01b039091169063d0fe96ae90602401602060405180830381865afa158015610d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d839190615265565b9050806001600160a01b0316856001600160a01b031614610ddd5760405162461bcd60e51b81526020600482015260146024820152732937baba32b91d103bb937b7339039b2b73232b960611b6044820152606401610293565b6001600160e01b03198616636b750d6360e01b14610e365760405162461bcd60e51b81526020600482015260166024820152752937baba32b91d103bb937b7339039b2b632b1ba37b960511b6044820152606401610293565b50600a80546001600160401b03851667ffffffffffffffff1990911617905560019150509392505050565b610e696111a5565b600d805460ff19166001179055610e82848484846113e8565b600d805460ff19169055610e966001600e55565b50505050565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929610ec6816110da565b6001600160a01b038316610f1c5760405162461bcd60e51b815260206004820152601d60248201527f556e6966696564526f7574657256323a207a65726f20616464726573730000006044820152606401610293565b6001600160a01b0383811660008181526011602090815260409182902080546001600160a01b031916948716948517905581519283528201929092527fec3d3c5fd0e9bfa5a7de49c176f7699b00e2fe558782f174a9d510c72218d69a910160405180910390a1505050565b604051605360f81b60208201526021016107fe565b60008181526006602052604081206107ce906116f3565b600082815260056020526040902060010154610fcf816110da565b61087c8383611131565b6000602083511015610ff557610fee836116fd565b90506107ce565b8161100084826152c8565b5060ff90506107ce565b6110148282610bc7565b6107e85760008281526005602090815260408083206001600160a01b03851684529091529020805460ff1916600117905561104c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610bc0836001600160a01b03841661173b565b60006001600160e01b03198216637965db0b60e01b14806107ce57506301ffc9a760e01b6001600160e01b03198316146107ce565b61090e813361178a565b6110ed816117e3565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b611119828261100a565b600082815260066020526040902061087c9082611090565b61113b8282611832565b600082815260066020526040902061087c9082611899565b61115b6118ae565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6002600e54036111f75760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610293565b6002600e55565b610100821061124f5760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a2077726f6e6720706172616d7320636f756e7400006044820152606401610293565b8051821461126f5760405162461bcd60e51b815260040161029390615387565b80518460ff16106112925760405162461bcd60e51b815260040161029390615387565b6000806000806112a78860ff168888886118f9565b93509350935093507f830adbcf80ee865e0f0883ad52e813fdbf061b0216b724694a2b4e06708d243c468a858786866040516112e8969594939291906153be565b60405180910390a1505050505050505050565b611303611cfd565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586111883390565b606060ff831461134b57610fee83611d43565b81805461135790615226565b80601f016020809104026020016040519081016040528092919081815260200182805461138390615226565b80156113d05780601f106113a5576101008083540402835291602001916113d0565b820191906000526020600020905b8154815290600101906020018083116113b357829003601f168201915b505050505090506107ce565b6000610bc08383611d82565b61010083106114395760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a2077726f6e6720706172616d7320636f756e7400006044820152606401610293565b815183146114595760405162461bcd60e51b815260040161029390615387565b6000611465344761541d565b90506000600460009054906101000a90046001600160a01b03166001600160a01b0316636fd7a80f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e09190615265565b90506000806114f0888888611dac565b604051631a4a8d3d60e21b81526004810183905291935091506001600160a01b0384169063692a34f4906024016020604051808303816000875af115801561153c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115609190615430565b15156001146115bf5760405162461bcd60e51b815260206004820152602560248201527f42617365526f757465723a20636f6d706c6578206f70206e6f742072656769736044820152641d195c995960da1b6064820152608401610293565b60006115cd33848489611e8f565b90506115da863582612042565b5050506000806000806115f060008b8b8b6118f9565b9296509094509250905047868111156116a457600033611610898461541d565b604051600081818185875af1925050503d806000811461164c576040519150601f19603f3d011682016040523d82523d6000602084013e611651565b606091505b50509050806116a25760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a206661696c656420746f2073656e642045544800006044820152606401610293565b505b7f830adbcf80ee865e0f0883ad52e813fdbf061b0216b724694a2b4e06708d243c466000868887876040516116de969594939291906153be565b60405180910390a15050505050505050505050565b60006107ce825490565b600080829050601f81511115611728578260405163305a27a960e01b81526004016102939190614da1565b805161173382615452565b179392505050565b6000818152600183016020526040812054611782575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107ce565b5060006107ce565b6117948282610bc7565b6107e8576117a18161217e565b6117ac836020612190565b6040516020016117bd929190615476565b60408051601f198184030181529082905262461bcd60e51b825261029391600401614da1565b6001600160a01b03811661090e5760405162461bcd60e51b8152602060048201526016602482015275456e64506f696e743a207a65726f206164647265737360501b6044820152606401610293565b61183c8282610bc7565b156107e85760008281526005602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610bc0836001600160a01b03841661232b565b60005460ff166118f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610293565b565b600080600080611907611cfd565b6040805160608101825260008082526020820181905291810191909152600c8790556060895b88811015611ce257600b819055600954611a06901580159061194e57508b82145b8b8b84818110611960576119606154eb565b90506020028101906119729190615501565b604051611980929190615547565b60405190819003902061199460018d61541d565b84106119a15760006119e6565b8c8c6119ae866001615557565b8181106119bd576119bd6154eb565b90506020028101906119cf9190615501565b6040516119dd929190615547565b60405180910390205b8b85815181106119f8576119f86154eb565b60200260200101518761241e565b92985091965090935091506000856002811115611a2557611a256151df565b14158a8a83818110611a3957611a396154eb565b9050602002810190611a4b9190615501565b604051602001611a5c92919061556a565b60405160208183030381529060405290611a895760405162461bcd60e51b81526004016102939190614da1565b509250826002856002811115611aa157611aa16151df565b14611ce2576001600160401b03861615611cd2576004805460405163687f4b5760e11b81526001600160401b038916928101929092526000916001600160a01b039091169063d0fe96ae90602401602060405180830381865afa158015611b0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b309190615265565b9050611b3c818861298b565b97508251600014611b665782898381518110611b5a57611b5a6154eb565b60200260200101819052505b6000636b750d6360e01b89848e8e8e604051602401611b89959493929190615627565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b0319909516949094179093526004805482516345d61ded60e01b815292519395506000946001600160a01b03909116936345d61ded9380840193908290030181865afa158015611c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c289190615265565b604051631d041f7b60e21b81529091506001600160a01b038216906374107dec90611c5e90859087908e906000906004016156eb565b600060405180830381600087803b158015611c7857600080fd5b505af1158015611c8c573d6000803e3d6000fd5b505050508a8481518110611ca257611ca26154eb565b6020026020010151600860008c81526020019081526020016000209081611cc991906152c8565b50505050611ce2565b611cdb81615730565b905061192d565b50506000600b819055600c5550929791965094509092509050565b60005460ff16156118f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610293565b60606000611d5083612abe565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000826000018281548110611d9957611d996154eb565b9060005260206000200154905092915050565b600060608060005b85811015611e7c5781878783818110611dcf57611dcf6154eb565b9050602002810190611de19190615501565b604051602001611df393929190615749565b60405160208183030381529060405291508251600003611e2e57848181518110611e1f57611e1f6154eb565b60200260200101519250611e6c565b82858281518110611e4157611e416154eb565b6020026020010151604051602001611e5a929190615771565b60405160208183030381529060405292505b611e7581615730565b9050611db4565b5080516020909101209590945092505050565b600080611e9b86612ae6565b905060007ff6ee28a1d07a7f08b92989953ec3452189f9f998ef0cb91641587f4f9a76c83b8783888888600001358960200135604051602001611ee497969594939291906157ad565b6040516020818303038152906040528051906020012090506000611f3d611f0a83612b0e565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b9050611f6281611f536060880160408901615806565b87606001358860800135612b3b565b93508460200135421115611faf5760405162461bcd60e51b815260206004820152601460248201527342617365526f757465723a20646561646c696e6560601b6044820152606401610293565b611fd97f369da55721ba2b3acddd63aac7d6512c3e5762a78fa01c44f423f97868330c3485610bc7565b6120375760405162461bcd60e51b815260206004820152602960248201527f42617365526f757465723a20696e76616c6964207369676e617475726520667260448201526837b6903bb7b935b2b960b91b6064820152608401610293565b505050949350505050565b811561213657813410156120915760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881a5b9d985b1a5908185b5bdd5b9d60521b6044820152606401610293565b6000816001600160a01b03168360405160006040518083038185875af1925050503d80600081146120de576040519150601f19603f3d011682016040523d82523d6000602084013e6120e3565b606091505b50509050806121345760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a206661696c656420746f2073656e64204574686572000000006044820152606401610293565b505b604080516001600160a01b03831681526020810184905233917fbf6afbaffb3b955bebbf43430bbf8eecb8d34ff86f293f592203ab5ed79c5268910160405180910390a25050565b60606107ce6001600160a01b03831660145b6060600061219f836002615823565b6121aa906002615557565b6001600160401b038111156121c1576121c1614e0e565b6040519080825280601f01601f1916602001820160405280156121eb576020820181803683370190505b509050600360fc1b81600081518110612206576122066154eb565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612235576122356154eb565b60200101906001600160f81b031916908160001a9053506000612259846002615823565b612264906001615557565b90505b60018111156122dc576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612298576122986154eb565b1a60f81b8282815181106122ae576122ae6154eb565b60200101906001600160f81b031916908160001a90535060049490941c936122d58161583a565b9050612267565b508315610bc05760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610293565b6000818152600183016020526040812054801561241457600061234f60018361541d565b85549091506000906123639060019061541d565b90508181146123c8576000866000018281548110612383576123836154eb565b90600052602060002001549050808760000184815481106123a6576123a66154eb565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806123d9576123d9615851565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107ce565b60009150506107ce565b604080516060818101835260008083526020830181905292820183905290600061244b8989898989612b65565b929650909450925090506000816002811115612469576124696151df565b0361297f5750604051604160f81b602082015260019088906021016040516020818303038152906040528051906020012003612654576000868060200190518101906124b59190615930565b905060006124c68260800151613892565b90506124e0826020015183604001518460e001518761390d565b6001600160a01b0390811660e08601819052911660408501526020840191909152606083015161251191468c613a21565b6001600160a01b031660608301528151604083015160208401516125389291908490613b41565b806001600160a01b031663dc64ef4583600001518460200151856060015186608001518760a001518860c001518960e001516040518863ffffffff1660e01b815260040161258c979695949392919061594d565b6020604051808303816000875af11580156125ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125cf919061598d565b80855260608301516001600160a01b03908116602087015260e084015116604086015260000361264d57600d5460ff16156126485760405162461bcd60e51b8152602060048201526019602482015278556e6966696564526f7574657256323a20736c69707061676560381b6044820152606401610293565b600292505b505061297f565b604051602960f91b60208201528890602101604051602081830303815290604052805190602001200361276e576000868060200190518101906126979190615930565b905060006126a88260800151613892565b90506126c2826020015183604001518460e001518761390d565b6001600160a01b0390811660e0860181905291166040850152602084019190915260608301516126f391468c613a21565b6001600160a01b0316606083015281516040830151602084015161271a9291908490613b41565b806001600160a01b031663cd7bfd5883600001518460200151856060015186608001518760a001518860c001518960e001516040518863ffffffff1660e01b815260040161258c979695949392919061594d565b604051605360f81b60208201528890602101604051602081830303815290604052805190602001200361297b576000868060200190518101906127b191906159a6565b905060006127c28260800151613892565b90506127dd826020015183604001518461010001518761390d565b6001600160a01b039081166101008601819052911660408501526020840191909152606083015161280f91468c613a21565b6001600160a01b031660608301528151604083015160208401516128369291908490613b41565b815160208301516060840151608085015160a086015160c087015160e0880151610100890151604051636469c44f60e01b81526001600160a01b039889166004820152602481019790975294871660448701529286166064860152608485019190915260ff90811660a48501521660c4830152821660e482015290821690636469c44f90610104016020604051808303816000875af11580156128dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612901919061598d565b80855260608301516001600160a01b03908116602087015261010084015116604086015260000361264d57600d5460ff16156126485760405162461bcd60e51b8152602060048201526019602482015278556e6966696564526f7574657256323a20736c69707061676560381b6044820152606401610293565b5060005b95509550955095915050565b60048054604080516345d61ded60e01b8152905160009384936001600160a01b0316926345d61ded92818301926020928290030181865afa1580156129d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f89190615265565b90506000816001600160a01b031663d087d2886040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a5e919061598d565b60408051306020808301919091528183018490526001600160401b03881660608301524660808301526001600160a01b03891660a0808401919091528351808403909101815260c090920190925280519101209091505b95945050505050565b600060ff8216601f8111156107ce57604051632cd44ac360e21b815260040160405180910390fd5b6001600160a01b03811660009081526007602052604090208054600181018255905b50919050565b60006107ce612b1b613b6d565b8360405161190160f01b8152600281019290925260228201526042902090565b6000806000612b4c87878787613c9d565b91509150612b5981613d61565b5090505b949350505050565b604080516060818101835260008083526020830181905292820183905290604051600560fc1b602082015260019088906021016040516020818303038152906040528051906020012003612d8857600b5415612c035760405162461bcd60e51b815260206004820152601a60248201527f526f757465723a207065726d6974206e6f7420616c6c6f7765640000000000006044820152606401610293565b600086806020019051810190612c199190615a4e565b805160208201516040808401516060850151608086015160a087015160c0880151945163d505accf60e01b81526001600160a01b0396871660048201523060248201526044810194909452606484019290925260ff16608483015260a482015260c4810191909152929350169063d505accf9060e401600060405180830381600087803b158015612ca957600080fd5b505af1925050508015612cba575060015b612d8257604080820151825160208401519251636eb1769f60e11b81526001600160a01b0393841660048201523060248201529192169063dd62ed3e90604401602060405180830381865afa158015612d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d3b919061598d565b1015612d825760405162461bcd60e51b8152602060048201526016602482015275526f757465723a207065726d6974206661696c75726560501b6044820152606401610293565b5061297f565b604051614c4d60f01b60208201528890602201604051602081830303815290604052805190602001201480612de3575060405161425560f01b6020820152889060220160405160208183030381529060405280519060200120145b80612e14575060405161424d60f01b6020820152889060220160405160208183030381529060405280519060200120145b156134cc57600086806020019051810190612e2f9190615ace565b90508915156000036133a057612e53816020015182604001518360c001518961390d565b6001600160a01b0390811660c0850181905291166040840152602083019190915260608201516080830151612e8992908b613a21565b6001600160a01b03166060820152604051614c4d60f01b60208201526000908a906022016040516020818303038152906040528051906020012003612ed657612ed182613eab565b6131dd565b6004805460405163d4f0cceb60e01b81526001600160401b034616928101929092526000916001600160a01b039091169063d4f0cceb90602401602060405180830381865afa158015612f2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f519190615265565b83516040516305b338c160e21b81526001600160a01b0391821660048201529192508216906316cce30490602401602060405180830381865afa158015612f9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc09190615265565b91506001600160a01b0382161561301a57806001600160a01b031683604001516001600160a01b0316146130065761300683600001518460400151838660200151613fd5565b6001600160a01b0381166040840152613161565b60048054604080516393e59dc160e01b815290516001600160a01b039092169260009284926393e59dc192818101926020929091908290030181865afa158015613068573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061308c9190615265565b855160405163166dbc3760e21b81526001600160a01b039182166004820152919250600091908316906359b6f0dc90602401602060405180830381865afa1580156130db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ff9190615b65565b60ff16101561315a5760405162461bcd60e51b815260206004820152602160248201527f526f757465723a2073796e7468206d7573742062652077686974656c697374656044820152601960fa1b6064820152608401610293565b5050825191505b806001600160a01b031663b6ff156a846000015185602001518660400151876060015188608001516040518663ffffffff1660e01b81526004016131a9959493929190615b82565b600060405180830381600087803b1580156131c357600080fd5b505af11580156131d7573d6000803e3d6000fd5b50505050505b81608001519550896040516020016131fd90614c4d60f01b815260020190565b6040516020818303038152906040528051906020012014613303576000819050806001600160a01b0316630e7c1cb56040518163ffffffff1660e01b8152600401602060405180830381865afa15801561325b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061327f9190615265565b6001600160a01b039081168452604080516306ed82dd60e31b815290519183169163376c16e8916004808201926020929091908290030181865afa1580156132cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132ef9190615bbd565b6001600160401b031660a084015250613313565b6001600160401b03461660a08301525b81604051602001613389919081516001600160a01b039081168252602080840151908301526040808401518216908301526060808401518216908301526080808401516001600160401b039081169184019190915260a0848101519091169083015260c092830151169181019190915260e00190565b604051602081830303815290604052945050612d82565b6009546000908152600f602052604081205460ff1660028111156133c6576133c66151df565b1461340a5760405162461bcd60e51b8152602060048201526014602482015273149bdd5d195c8e881bdc081c1c9bd8d95cdcd95960621b6044820152606401610293565b6009546000908152600f60205260409020805460ff1916600117905560608101516001600160a01b031661345f5761345081606001518260c0015183608001518b613a21565b6001600160a01b031660608201525b60405161425560f01b60208201528990602201604051602081830303815290604052805190602001201461349b5761349681614040565b6134a4565b6134a481614147565b835260608101516001600160a01b03908116602085015260c08201511660408401525061297f565b604051605760f81b60208201528890602101604051602081830303815290604052805190602001201480613526575060405161557760f01b6020820152889060220160405160208183030381529060405280519060200120145b15613601576000868060200190518101906135419190615bda565b9050600061355a8260200151836040015160008a61390d565b6001600160a01b039091166040850152602084019190915260608301519091506135869080468c613a21565b6001600160a01b03166060830152604051605760f81b60208201528a9060210160405160208183030381529060405280519060200120146135cf576135ca82614205565b6135d8565b6135d8826143ae565b845250606001516001600160a01b0390811660208401526040868101519091169083015261297f565b60405161214d60f01b6020820152889060220160405160208183030381529060405280519060200120148061365c575060405161215560f01b6020820152889060220160405160208183030381529060405280519060200120145b15613880576000868060200190518101906136779190615c55565b905089151560000361371657600181516000908152600f602052604090205460ff1660028111156136aa576136aa6151df565b036136ee5760405162461bcd60e51b8152602060048201526014602482015273149bdd5d195c8e881bdc081c1c9bd8d95cdcd95960621b6044820152606401610293565b80516000908152600f60209081526040909120805460ff191660021790558101519450612d82565b80516000908152600860205260408120805461373190615226565b80601f016020809104026020016040519081016040528092919081815260200182805461375d90615226565b80156137aa5780601f1061377f576101008083540402835291602001916137aa565b820191906000526020600020905b81548152906001019060200180831161378d57829003601f168201915b5050505050905080516000036137fb5760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881bdc081b9bdd081cdd185c9d195960521b6044820152606401610293565b6000818060200190518101906138119190615ace565b8351600090815260086020526040812091925061382e9190614c55565b60405161214d60f01b60208201528b90602201604051602081830303815290604052805190602001200361386c57613865816144ca565b8552613878565b613875816145ed565b85525b50505061297f565b50839050600095509550955095915050565b6001600160a01b0380821660009081526011602052604090205416806139085760405162461bcd60e51b815260206004820152602560248201527f556e6966696564526f7574657256323a20706f6f6c2061646170746572206e6f6044820152641d081cd95d60da1b6064820152608401610293565b919050565b600080600060001987146139215786613924565b83515b92506001600160a01b0386161561398c576001600160a01b03861633146139845760405162461bcd60e51b81526020600482015260146024820152732937baba32b91d103bb937b7339039b2b73232b960611b6044820152606401610293565b859150613994565b836020015191505b6009541580156139ac57506001600160a01b03851615155b15613a10576001600160a01b0385163314613a095760405162461bcd60e51b815260206004820152601960248201527f526f757465723a2077726f6e6720656d657267656e6379546f000000000000006044820152606401610293565b5083613a17565b5060408301515b9450945094915050565b6000613a2f85858585614797565b90506001600160a01b038116612b5d57604051604160f81b602082015260210160405160208183030381529060405280519060200120821480613a965750604051602960f91b60208201526021016040516020818303038152906040528051906020012082145b80613ac55750604051605360f81b60208201526021016040516020818303038152906040528051906020012082145b15612b5d576004805460405163687f4b5760e11b81526001600160401b038616928101929092526001600160a01b03169063d0fe96ae906024015b602060405180830381865afa158015613b1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab59190615265565b306001600160a01b03841603613b6157613b5c848383614a2d565b610e96565b610e9684848484613fd5565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015613bc657507f000000000000000000000000000000000000000000000000000000000000000046145b15613bf057507f000000000000000000000000000000000000000000000000000000000000000090565b613c98604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613cd45750600090506003613d58565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613d28573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613d5157600060019250925050613d58565b9150600090505b94509492505050565b6000816004811115613d7557613d756151df565b03613d7d5750565b6001816004811115613d9157613d916151df565b03613dde5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610293565b6002816004811115613df257613df26151df565b03613e3f5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610293565b6003816004811115613e5357613e536151df565b0361090e5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610293565b60048054604051630f5427af60e41b81526001600160401b034616928101929092526000916001600160a01b039091169063f5427af090602401602060405180830381865afa158015613f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f269190615265565b9050806001600160a01b031682604001516001600160a01b031614613f5d57613f5d82600001518360400151838560200151613fd5565b806001600160a01b0316633fea56b883600001518460200151856040015186606001516040518563ffffffff1660e01b8152600401613f9f9493929190615caa565b600060405180830381600087803b158015613fb957600080fd5b505af1158015613fcd573d6000803e3d6000fd5b505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052610e969085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614a5d565b6004805460405163d4f0cceb60e01b81526001600160401b0346169281019290925260009182916001600160a01b03169063d4f0cceb90602401602060405180830381865afa158015614097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140bb9190615265565b83516020850151604080870151606088015160a0890151925163df543e8160e01b81529596506001600160a01b0387169563df543e819561410495909490939291600401615b82565b6020604051808303816000875af1158015614123573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc0919061598d565b60048054604051630f5427af60e41b81526001600160401b0346169281019290925260009182916001600160a01b03169063f5427af090602401602060405180830381865afa15801561419e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c29190615265565b8351602085015160408087015160608801519151637f27a5b960e11b81529495506001600160a01b0386169463fe4f4b7294614104949093909291600401615caa565b60006001600c54614216919061541d565b600b54146142665760405162461bcd60e51b815260206004820152601a60248201527f526f757465723a20756e77726170206e6f7420616c6c6f7765640000000000006044820152606401610293565b60408201516001600160a01b031630146142925761429282600001518360400151308560200151613fd5565b81516020830151604051632e1a7d4d60e01b81526001600160a01b0390921691632e1a7d4d916142c89160040190815260200190565b600060405180830381600087803b1580156142e257600080fd5b505af11580156142f6573d6000803e3d6000fd5b50505050600082606001516001600160a01b0316836020015160405160006040518083038185875af1925050503d806000811461434f576040519150601f19603f3d011682016040523d82523d6000602084013e614354565b606091505b50509050806143a55760405162461bcd60e51b815260206004820152601a60248201527f526f757465723a206661696c656420746f2073656e64204554480000000000006044820152606401610293565b50506020015190565b6000600b546000146144025760405162461bcd60e51b815260206004820152601860248201527f526f757465723a2077726170206e6f7420616c6c6f77656400000000000000006044820152606401610293565b816020015134101561444f5760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881a5b9d985b1a5908185b5bdd5b9d60521b6044820152606401610293565b81600001516001600160a01b031663d0e30db083602001516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561449257600080fd5b505af11580156144a6573d6000803e3d6000fd5b50505050506144c2826000015183606001518460200151614a2d565b506020015190565b6080810151600a546000916001600160401b0391821691161461452f5760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a2077726f6e6720656d657267656e637920696e6974000000006044820152606401610293565b60048054604051630f5427af60e41b81526001600160401b034616928101929092526000916001600160a01b039091169063f5427af090602401602060405180830381865afa158015614586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145aa9190615265565b8351602085015160408087015160c0880151915163c26b5bab60e01b81529495506001600160a01b0386169463c26b5bab94614104949093909291600401615caa565b6080810151600a546000916001600160401b039182169116146146525760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a2077726f6e6720656d657267656e637920696e6974000000006044820152606401610293565b6004805460405163d4f0cceb60e01b81526001600160401b034616928101929092526000916001600160a01b039091169063d4f0cceb90602401602060405180830381865afa1580156146a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146cd9190615265565b60a08401518451604051637f9fa89f60e01b81526001600160401b0390921660048301526001600160a01b03908116602483015291925090821690637f9fa89f90604401602060405180830381865afa15801561472e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147529190615265565b6001600160a01b03908116808552602085015160408087015160c0880151915163550bf7db60e11b81529486169463aa17efb694614104949093909291600401615caa565b60006001600160a01b03851615806147ad575081155b6147ec5760405162461bcd60e51b815260206004820152601060248201526f526f757465723a2077726f6e6720746f60801b6044820152606401610293565b8161485357849050836001600160a01b0316816001600160a01b03161461484e5760405162461bcd60e51b81526020600482015260166024820152752937baba32b91d103bb937b733903932b1b2b4bb32b960511b6044820152606401610293565b612b5d565b604051614c4d60f01b60208201526022016040516020818303038152906040528051906020012082036148fe5760048054604051630f5427af60e41b81526001600160401b038616928101929092526001600160a01b03169063f5427af0906024015b602060405180830381865afa1580156148d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f79190615265565b9050612b5d565b60405161425560f01b602082015260220160405160208183030381529060405280519060200120821480614957575060405161424d60f01b60208201526022016040516020818303038152906040528051906020012082145b15614996576004805460405163d4f0cceb60e01b81526001600160401b038616928101929092526001600160a01b03169063d4f0cceb906024016148b6565b604051605760f81b60208201528290602101604051602081830303815290604052805190602001201480613ac5575060405161557760f01b602082015282906022016040516020818303038152906040528051906020012003612b5d576004805460405163687f4b5760e11b81526001600160401b038616928101929092526001600160a01b03169063d0fe96ae90602401613b00565b6040516001600160a01b03831660248201526044810182905261087c90849063a9059cbb60e01b90606401614009565b6000614ab2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614b329092919063ffffffff16565b9050805160001480614ad3575080806020019051810190614ad39190615430565b61087c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610293565b6060612b5d848460008585600080866001600160a01b03168587604051614b599190615cd5565b60006040518083038185875af1925050503d8060008114614b96576040519150601f19603f3d011682016040523d82523d6000602084013e614b9b565b606091505b5091509150614bac87838387614bb7565b979650505050505050565b60608315614c26578251600003614c1f576001600160a01b0385163b614c1f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610293565b5081612b5d565b612b5d8383815115614c3b5781518083602001fd5b8060405162461bcd60e51b81526004016102939190614da1565b508054614c6190615226565b6000825580601f10614c71575050565b601f01602090049060005260206000209081019061090e91905b80821115614c9f5760008155600101614c8b565b5090565b80356001600160e01b03198116811461390857600080fd5b600060208284031215614ccd57600080fd5b610bc082614ca3565b6001600160a01b038116811461090e57600080fd5b600060208284031215614cfd57600080fd5b8135610bc081614cd6565b600060208284031215614d1a57600080fd5b5035919050565b60008060408385031215614d3457600080fd5b823591506020830135614d4681614cd6565b809150509250929050565b60005b83811015614d6c578181015183820152602001614d54565b50506000910152565b60008151808452614d8d816020860160208601614d51565b601f01601f19169290920160200192915050565b602081526000610bc06020830184614d75565b60ff8116811461090e57600080fd5b60008083601f840112614dd557600080fd5b5081356001600160401b03811115614dec57600080fd5b6020830191508360208260051b8501011115614e0757600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b0381118282101715614e4757614e47614e0e565b60405290565b60405160e081016001600160401b0381118282101715614e4757614e47614e0e565b604051601f8201601f191681016001600160401b0381118282101715614e9757614e97614e0e565b604052919050565b6000601f8381840112614eb157600080fd5b823560206001600160401b0380831115614ecd57614ecd614e0e565b8260051b614edc838201614e6f565b9384528681018301938381019089861115614ef657600080fd5b84890192505b85831015614f8657823584811115614f145760008081fd5b8901603f81018b13614f265760008081fd5b85810135604086821115614f3c57614f3c614e0e565b614f4d828b01601f19168901614e6f565b8281528d82848601011115614f625760008081fd5b828285018a8301376000928101890192909252508352509184019190840190614efc565b9998505050505050505050565b600080600080600060808688031215614fab57600080fd5b853594506020860135614fbd81614db4565b935060408601356001600160401b0380821115614fd957600080fd5b614fe589838a01614dc3565b90955093506060880135915080821115614ffe57600080fd5b5061500b88828901614e9f565b9150509295509295909350565b60ff60f81b881681526000602060e08184015261503860e084018a614d75565b838103604085015261504a818a614d75565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b8181101561509c57835183529284019291840191600101615080565b50909c9b505050505050505050505050565b600080604083850312156150c157600080fd5b50508035926020909101359150565b6001600160401b038116811461090e57600080fd5b6000806000606084860312156150fa57600080fd5b61510384614ca3565b9250602084013561511381614cd6565b91506040840135615123816150d0565b809150509250925092565b60008060008084860360e081121561514557600080fd5b85356001600160401b038082111561515c57600080fd5b61516889838a01614dc3565b9097509550602088013591508082111561518157600080fd5b5061518e88828901614e9f565b93505060a0603f19820112156151a357600080fd5b509295919450926040019150565b600080604083850312156151c457600080fd5b82356151cf81614cd6565b91506020830135614d4681614cd6565b634e487b7160e01b600052602160045260246000fd5b6003811061090e57634e487b7160e01b600052602160045260246000fd5b60208101615220836151f5565b91905290565b600181811c9082168061523a57607f821691505b602082108103612b0857634e487b7160e01b600052602260045260246000fd5b805161390881614cd6565b60006020828403121561527757600080fd5b8151610bc081614cd6565b601f82111561087c57600081815260208120601f850160051c810160208610156152a95750805b601f850160051c820191505b81811015613fcd578281556001016152b5565b81516001600160401b038111156152e1576152e1614e0e565b6152f5816152ef8454615226565b84615282565b602080601f83116001811461532a57600084156153125750858301515b600019600386901b1c1916600185901b178555613fcd565b600085815260208120601f198616915b828110156153595788860151825594840194600190910190840161533a565b50858210156153775787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60208082526018908201527f42617365526f757465723a2077726f6e6720706172616d730000000000000000604082015260600190565b6001600160401b03878116825260208201879052851660408201526060810184905260c081016153ed846151f5565b83608083015260ff831660a0830152979650505050505050565b634e487b7160e01b600052601160045260246000fd5b818103818111156107ce576107ce615407565b60006020828403121561544257600080fd5b81518015158114610bc057600080fd5b80516020808301519190811015612b085760001960209190910360031b1b16919050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516154ae816017850160208801614d51565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516154df816028840160208801614d51565b01602801949350505050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261551857600080fd5b8301803591506001600160401b0382111561553257600080fd5b602001915036819003821315614e0757600080fd5b8183823760009101908152919050565b808201808211156107ce576107ce615407565b6a02937baba32b91d1037b8160ad1b81528183600b83013770081a5cc81b9bdd081cdd5c1c1bdc9d1959607a1b9101600b810191909152601c01919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526020808501808196508360051b8101915082860160005b8581101561561a578284038952615608848351614d75565b988501989350908401906001016155f0565b5091979650505050505050565b600060808201878352602060ff881681850152608060408501528186835260a08501905060a08760051b86010192508760005b888110156156c957868503609f190183528135368b9003601e1901811261568057600080fd5b8a0184810190356001600160401b0381111561569b57600080fd5b8036038213156156aa57600080fd5b6156b58782846155a9565b96505050918301919083019060010161565a565b5050505082810360608401526156df81856155d2565b98975050505050505050565b6080815260006156fe6080830187614d75565b6001600160a01b0395861660208401526001600160401b03949094166040830152509216606090920191909152919050565b60006001820161574257615742615407565b5060010190565b6000845161575b818460208901614d51565b8201838582376000930192835250909392505050565b60008351615783818460208801614d51565b600b60fa1b90830190815283516157a1816001840160208801614d51565b01600101949350505050565b8781526bffffffffffffffffffffffff198760601b166020820152856034820152846054820152600084516157e9816074850160208901614d51565b909101607481019390935250609482015260b40195945050505050565b60006020828403121561581857600080fd5b8135610bc081614db4565b80820281158282048414176107ce576107ce615407565b60008161584957615849615407565b506000190190565b634e487b7160e01b600052603160045260246000fd5b805161390881614db4565b600061010080838503121561588657600080fd5b604051908101906001600160401b03821181831017156158a8576158a8614e0e565b81604052809250835191506158bc82614cd6565b818152602084015160208201526158d56040850161525a565b60408201526158e66060850161525a565b60608201526158f76080850161525a565b608082015260a084015160a082015261591260c08501615867565b60c082015261592360e0850161525a565b60e0820152505092915050565b6000610100828403121561594357600080fd5b610bc08383615872565b6001600160a01b039788168152602081019690965293861660408601529185166060850152608084015260ff1660a083015290911660c082015260e00190565b60006020828403121561599f57600080fd5b5051919050565b600061012082840312156159b957600080fd5b6159c1614e24565b6159ca8361525a565b8152602083015160208201526159e26040840161525a565b60408201526159f36060840161525a565b6060820152615a046080840161525a565b608082015260a083015160a0820152615a1f60c08401615867565b60c0820152615a3060e08401615867565b60e0820152610100615a4381850161525a565b908201529392505050565b600060e08284031215615a6057600080fd5b615a68614e4d565b8251615a7381614cd6565b81526020830151615a8381614cd6565b8060208301525060408301516040820152606083015160608201526080830151615aac81614db4565b608082015260a0838101519082015260c0928301519281019290925250919050565b600060e08284031215615ae057600080fd5b615ae8614e4d565b8251615af381614cd6565b8152602083810151908201526040830151615b0d81614cd6565b60408201526060830151615b2081614cd6565b60608201526080830151615b33816150d0565b608082015260a0830151615b46816150d0565b60a082015260c0830151615b5981614cd6565b60c08201529392505050565b600060208284031215615b7757600080fd5b8151610bc081614db4565b6001600160a01b0395861681526020810194909452918416604084015290921660608201526001600160401b03909116608082015260a00190565b600060208284031215615bcf57600080fd5b8151610bc0816150d0565b600060808284031215615bec57600080fd5b604051608081018181106001600160401b0382111715615c0e57615c0e614e0e565b6040528251615c1c81614cd6565b8152602083810151908201526040830151615c3681614cd6565b60408201526060830151615c4981614cd6565b60608201529392505050565b600060408284031215615c6757600080fd5b604051604081018181106001600160401b0382111715615c8957615c89614e0e565b604052825181526020830151615c9e816150d0565b60208201529392505050565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b60008251615ce7818460208701614d51565b919091019291505056fea26469706673582212205776d4f17c3c44a385839b60318559289acc63e8147e482d5e9619bd852ff16864736f6c634300081100330000000000000000000000009bbc7661af64d7af74f41ffee71a2b2798900d31
Deployed Bytecode
0x60806040526004361061023f5760003560e01c806384b0196e1161012e578063ad5c4648116100ab578063ca15c8731161006f578063ca15c873146106d8578063d547741f146106f8578063f5887cdd14610718578063f5b541a614610738578063f87cf42b1461076c57600080fd5b8063ad5c464814610650578063b4ccca0d14610670578063ba677db714610690578063bcf4f0a6146106a3578063beadbe32146106c357600080fd5b80639bb68c75116100f25780639bb68c75146105bd578063a217fddf146105d2578063a785ac5a146105e7578063ab1efbab14610607578063ad351f9f1461063b57600080fd5b806384b0196e1461050a5780639010d07c1461053257806391d148541461055257806395ad709a146105725780639ba520ad146105a857600080fd5b80633e7e25c1116101bc5780636b750d63116101805780636b750d631461048b57806376a3fb3e146104ab578063778c89b9146104c05780637ecebe00146104d55780638456cb59146104f557600080fd5b80633e7e25c1146104005780633f4ba83a1461042757806354fd4d501461043c5780635c975abb1461045e5780636869cb961461047657600080fd5b80632b385bcf116102035780632b385bcf146103815780632d07ae69146103965780632ee63e44146103ab5780632f2ff15d146103c057806336568abe146103e057600080fd5b806301ffc9a7146102a35780630b3448a8146102d85780630e03e490146102f85780630ff53ba71461032e578063248a9ca31461035157600080fd5b3661029e576010546001600160a01b0316331461029c5760405162461bcd60e51b81526020600482015260166024820152752937baba32b91d1024b73b30b634b21039b2b73232b960511b60448201526064015b60405180910390fd5b005b600080fd5b3480156102af57600080fd5b506102c36102be366004614cbb565b6107a9565b60405190151581526020015b60405180910390f35b3480156102e457600080fd5b5061029c6102f3366004614ceb565b6107d4565b34801561030457600080fd5b50610316610313366004614d08565b90565b6040516001600160a01b0390911681526020016102cf565b34801561033a57600080fd5b506103436107ec565b6040519081526020016102cf565b34801561035d57600080fd5b5061034361036c366004614d08565b60009081526005602052604090206001015490565b34801561038d57600080fd5b50610343610817565b3480156103a257600080fd5b5061034361082c565b3480156103b757600080fd5b50610343610841565b3480156103cc57600080fd5b5061029c6103db366004614d21565b610857565b3480156103ec57600080fd5b5061029c6103fb366004614d21565b610881565b34801561040c57600080fd5b5061034361041b366004614ceb565b6001600160a01b031690565b34801561043357600080fd5b5061029c6108fb565b34801561044857600080fd5b50610451610911565b6040516102cf9190614da1565b34801561046a57600080fd5b5060005460ff166102c3565b34801561048257600080fd5b5061034361099f565b34801561049757600080fd5b5061029c6104a6366004614f93565b6109b5565b3480156104b757600080fd5b50610343610ac2565b3480156104cc57600080fd5b50610343610ad8565b3480156104e157600080fd5b506103436104f0366004614ceb565b610aee565b34801561050157600080fd5b5061029c610b0c565b34801561051657600080fd5b5061051f610b1f565b6040516102cf9796959493929190615018565b34801561053e57600080fd5b5061031661054d3660046150ae565b610ba8565b34801561055e57600080fd5b506102c361056d366004614d21565b610bc7565b34801561057e57600080fd5b5061031661058d366004614ceb565b6011602052600090815260409020546001600160a01b031681565b3480156105b457600080fd5b50610343610bf2565b3480156105c957600080fd5b50610343610c07565b3480156105de57600080fd5b50610343600081565b3480156105f357600080fd5b50610451610602366004614d08565b610c1d565b34801561061357600080fd5b506103437f369da55721ba2b3acddd63aac7d6512c3e5762a78fa01c44f423f97868330c3481565b34801561064757600080fd5b50610343610c36565b34801561065c57600080fd5b50601054610316906001600160a01b031681565b34801561067c57600080fd5b506102c361068b3660046150e5565b610c4b565b61029c61069e36600461512e565b610e61565b3480156106af57600080fd5b5061029c6106be3660046151b1565b610e9c565b3480156106cf57600080fd5b50610343610f88565b3480156106e457600080fd5b506103436106f3366004614d08565b610f9d565b34801561070457600080fd5b5061029c610713366004614d21565b610fb4565b34801561072457600080fd5b50600454610316906001600160a01b031681565b34801561074457600080fd5b506103437f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b34801561077857600080fd5b5061079c610787366004614d08565b600f6020526000908152604090205460ff1681565b6040516102cf9190615213565b60006001600160e01b03198216635a05180f60e01b14806107ce57506107ce826110a5565b92915050565b60006107df816110da565b6107e8826110e4565b5050565b60405161215560f01b60208201526022015b6040516020818303038152906040528051906020012081565b604051605760f81b60208201526021016107fe565b604051602960f91b60208201526021016107fe565b604051614c4d60f01b60208201526022016107fe565b600082815260056020526040902060010154610872816110da565b61087c838361110f565b505050565b6001600160a01b03811633146108f15760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610293565b6107e88282611131565b6000610906816110da565b61090e611153565b50565b6003805461091e90615226565b80601f016020809104026020016040519081016040528092919081815260200182805461094a90615226565b80156109975780601f1061096c57610100808354040283529160200191610997565b820191906000526020600020905b81548152906001019060200180831161097a57829003601f168201915b505050505081565b60405161424d60f01b60208201526022016107fe565b6109bd6111a5565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e78cea926040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a369190615265565b90506001600160a01b0381163314610a865760405162461bcd60e51b8152602060048201526013602482015272526f757465723a20627269646765206f6e6c7960681b6044820152606401610293565b600986905585610a9981878787876111fe565b50506000600955600a805467ffffffffffffffff19169055610abb6001600e55565b5050505050565b60405161425560f01b60208201526022016107fe565b60405161557760f01b60208201526022016107fe565b6001600160a01b0381166000908152600760205260408120546107ce565b6000610b17816110da565b61090e6112fb565b600060608082808083610b537f45595741000000000000000000000000000000000000000000000000000000046001611338565b610b7e7f31000000000000000000000000000000000000000000000000000000000000016002611338565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6000828152600660205260408120610bc090836113dc565b9392505050565b60009182526005602090815260408084206001600160a01b0393909316845291905290205460ff1690565b604051604160f81b60208201526021016107fe565b60405161214d60f01b60208201526022016107fe565b6008602052600090815260409020805461091e90615226565b604051600560fc1b60208201526021016107fe565b60048054604080516373c6754960e11b8152905160009384936001600160a01b03169263e78cea9292818301926020928290030181865afa158015610c94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb89190615265565b90506001600160a01b0381163314610d085760405162461bcd60e51b8152602060048201526013602482015272526f757465723a20627269646765206f6e6c7960681b6044820152606401610293565b6004805460405163687f4b5760e11b81526001600160401b038616928101929092526000916001600160a01b039091169063d0fe96ae90602401602060405180830381865afa158015610d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d839190615265565b9050806001600160a01b0316856001600160a01b031614610ddd5760405162461bcd60e51b81526020600482015260146024820152732937baba32b91d103bb937b7339039b2b73232b960611b6044820152606401610293565b6001600160e01b03198616636b750d6360e01b14610e365760405162461bcd60e51b81526020600482015260166024820152752937baba32b91d103bb937b7339039b2b632b1ba37b960511b6044820152606401610293565b50600a80546001600160401b03851667ffffffffffffffff1990911617905560019150509392505050565b610e696111a5565b600d805460ff19166001179055610e82848484846113e8565b600d805460ff19169055610e966001600e55565b50505050565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929610ec6816110da565b6001600160a01b038316610f1c5760405162461bcd60e51b815260206004820152601d60248201527f556e6966696564526f7574657256323a207a65726f20616464726573730000006044820152606401610293565b6001600160a01b0383811660008181526011602090815260409182902080546001600160a01b031916948716948517905581519283528201929092527fec3d3c5fd0e9bfa5a7de49c176f7699b00e2fe558782f174a9d510c72218d69a910160405180910390a1505050565b604051605360f81b60208201526021016107fe565b60008181526006602052604081206107ce906116f3565b600082815260056020526040902060010154610fcf816110da565b61087c8383611131565b6000602083511015610ff557610fee836116fd565b90506107ce565b8161100084826152c8565b5060ff90506107ce565b6110148282610bc7565b6107e85760008281526005602090815260408083206001600160a01b03851684529091529020805460ff1916600117905561104c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610bc0836001600160a01b03841661173b565b60006001600160e01b03198216637965db0b60e01b14806107ce57506301ffc9a760e01b6001600160e01b03198316146107ce565b61090e813361178a565b6110ed816117e3565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b611119828261100a565b600082815260066020526040902061087c9082611090565b61113b8282611832565b600082815260066020526040902061087c9082611899565b61115b6118ae565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6002600e54036111f75760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610293565b6002600e55565b610100821061124f5760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a2077726f6e6720706172616d7320636f756e7400006044820152606401610293565b8051821461126f5760405162461bcd60e51b815260040161029390615387565b80518460ff16106112925760405162461bcd60e51b815260040161029390615387565b6000806000806112a78860ff168888886118f9565b93509350935093507f830adbcf80ee865e0f0883ad52e813fdbf061b0216b724694a2b4e06708d243c468a858786866040516112e8969594939291906153be565b60405180910390a1505050505050505050565b611303611cfd565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586111883390565b606060ff831461134b57610fee83611d43565b81805461135790615226565b80601f016020809104026020016040519081016040528092919081815260200182805461138390615226565b80156113d05780601f106113a5576101008083540402835291602001916113d0565b820191906000526020600020905b8154815290600101906020018083116113b357829003601f168201915b505050505090506107ce565b6000610bc08383611d82565b61010083106114395760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a2077726f6e6720706172616d7320636f756e7400006044820152606401610293565b815183146114595760405162461bcd60e51b815260040161029390615387565b6000611465344761541d565b90506000600460009054906101000a90046001600160a01b03166001600160a01b0316636fd7a80f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e09190615265565b90506000806114f0888888611dac565b604051631a4a8d3d60e21b81526004810183905291935091506001600160a01b0384169063692a34f4906024016020604051808303816000875af115801561153c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115609190615430565b15156001146115bf5760405162461bcd60e51b815260206004820152602560248201527f42617365526f757465723a20636f6d706c6578206f70206e6f742072656769736044820152641d195c995960da1b6064820152608401610293565b60006115cd33848489611e8f565b90506115da863582612042565b5050506000806000806115f060008b8b8b6118f9565b9296509094509250905047868111156116a457600033611610898461541d565b604051600081818185875af1925050503d806000811461164c576040519150601f19603f3d011682016040523d82523d6000602084013e611651565b606091505b50509050806116a25760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a206661696c656420746f2073656e642045544800006044820152606401610293565b505b7f830adbcf80ee865e0f0883ad52e813fdbf061b0216b724694a2b4e06708d243c466000868887876040516116de969594939291906153be565b60405180910390a15050505050505050505050565b60006107ce825490565b600080829050601f81511115611728578260405163305a27a960e01b81526004016102939190614da1565b805161173382615452565b179392505050565b6000818152600183016020526040812054611782575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107ce565b5060006107ce565b6117948282610bc7565b6107e8576117a18161217e565b6117ac836020612190565b6040516020016117bd929190615476565b60408051601f198184030181529082905262461bcd60e51b825261029391600401614da1565b6001600160a01b03811661090e5760405162461bcd60e51b8152602060048201526016602482015275456e64506f696e743a207a65726f206164647265737360501b6044820152606401610293565b61183c8282610bc7565b156107e85760008281526005602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610bc0836001600160a01b03841661232b565b60005460ff166118f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610293565b565b600080600080611907611cfd565b6040805160608101825260008082526020820181905291810191909152600c8790556060895b88811015611ce257600b819055600954611a06901580159061194e57508b82145b8b8b84818110611960576119606154eb565b90506020028101906119729190615501565b604051611980929190615547565b60405190819003902061199460018d61541d565b84106119a15760006119e6565b8c8c6119ae866001615557565b8181106119bd576119bd6154eb565b90506020028101906119cf9190615501565b6040516119dd929190615547565b60405180910390205b8b85815181106119f8576119f86154eb565b60200260200101518761241e565b92985091965090935091506000856002811115611a2557611a256151df565b14158a8a83818110611a3957611a396154eb565b9050602002810190611a4b9190615501565b604051602001611a5c92919061556a565b60405160208183030381529060405290611a895760405162461bcd60e51b81526004016102939190614da1565b509250826002856002811115611aa157611aa16151df565b14611ce2576001600160401b03861615611cd2576004805460405163687f4b5760e11b81526001600160401b038916928101929092526000916001600160a01b039091169063d0fe96ae90602401602060405180830381865afa158015611b0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b309190615265565b9050611b3c818861298b565b97508251600014611b665782898381518110611b5a57611b5a6154eb565b60200260200101819052505b6000636b750d6360e01b89848e8e8e604051602401611b89959493929190615627565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b0319909516949094179093526004805482516345d61ded60e01b815292519395506000946001600160a01b03909116936345d61ded9380840193908290030181865afa158015611c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c289190615265565b604051631d041f7b60e21b81529091506001600160a01b038216906374107dec90611c5e90859087908e906000906004016156eb565b600060405180830381600087803b158015611c7857600080fd5b505af1158015611c8c573d6000803e3d6000fd5b505050508a8481518110611ca257611ca26154eb565b6020026020010151600860008c81526020019081526020016000209081611cc991906152c8565b50505050611ce2565b611cdb81615730565b905061192d565b50506000600b819055600c5550929791965094509092509050565b60005460ff16156118f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610293565b60606000611d5083612abe565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000826000018281548110611d9957611d996154eb565b9060005260206000200154905092915050565b600060608060005b85811015611e7c5781878783818110611dcf57611dcf6154eb565b9050602002810190611de19190615501565b604051602001611df393929190615749565b60405160208183030381529060405291508251600003611e2e57848181518110611e1f57611e1f6154eb565b60200260200101519250611e6c565b82858281518110611e4157611e416154eb565b6020026020010151604051602001611e5a929190615771565b60405160208183030381529060405292505b611e7581615730565b9050611db4565b5080516020909101209590945092505050565b600080611e9b86612ae6565b905060007ff6ee28a1d07a7f08b92989953ec3452189f9f998ef0cb91641587f4f9a76c83b8783888888600001358960200135604051602001611ee497969594939291906157ad565b6040516020818303038152906040528051906020012090506000611f3d611f0a83612b0e565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b9050611f6281611f536060880160408901615806565b87606001358860800135612b3b565b93508460200135421115611faf5760405162461bcd60e51b815260206004820152601460248201527342617365526f757465723a20646561646c696e6560601b6044820152606401610293565b611fd97f369da55721ba2b3acddd63aac7d6512c3e5762a78fa01c44f423f97868330c3485610bc7565b6120375760405162461bcd60e51b815260206004820152602960248201527f42617365526f757465723a20696e76616c6964207369676e617475726520667260448201526837b6903bb7b935b2b960b91b6064820152608401610293565b505050949350505050565b811561213657813410156120915760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881a5b9d985b1a5908185b5bdd5b9d60521b6044820152606401610293565b6000816001600160a01b03168360405160006040518083038185875af1925050503d80600081146120de576040519150601f19603f3d011682016040523d82523d6000602084013e6120e3565b606091505b50509050806121345760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a206661696c656420746f2073656e64204574686572000000006044820152606401610293565b505b604080516001600160a01b03831681526020810184905233917fbf6afbaffb3b955bebbf43430bbf8eecb8d34ff86f293f592203ab5ed79c5268910160405180910390a25050565b60606107ce6001600160a01b03831660145b6060600061219f836002615823565b6121aa906002615557565b6001600160401b038111156121c1576121c1614e0e565b6040519080825280601f01601f1916602001820160405280156121eb576020820181803683370190505b509050600360fc1b81600081518110612206576122066154eb565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612235576122356154eb565b60200101906001600160f81b031916908160001a9053506000612259846002615823565b612264906001615557565b90505b60018111156122dc576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612298576122986154eb565b1a60f81b8282815181106122ae576122ae6154eb565b60200101906001600160f81b031916908160001a90535060049490941c936122d58161583a565b9050612267565b508315610bc05760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610293565b6000818152600183016020526040812054801561241457600061234f60018361541d565b85549091506000906123639060019061541d565b90508181146123c8576000866000018281548110612383576123836154eb565b90600052602060002001549050808760000184815481106123a6576123a66154eb565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806123d9576123d9615851565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107ce565b60009150506107ce565b604080516060818101835260008083526020830181905292820183905290600061244b8989898989612b65565b929650909450925090506000816002811115612469576124696151df565b0361297f5750604051604160f81b602082015260019088906021016040516020818303038152906040528051906020012003612654576000868060200190518101906124b59190615930565b905060006124c68260800151613892565b90506124e0826020015183604001518460e001518761390d565b6001600160a01b0390811660e08601819052911660408501526020840191909152606083015161251191468c613a21565b6001600160a01b031660608301528151604083015160208401516125389291908490613b41565b806001600160a01b031663dc64ef4583600001518460200151856060015186608001518760a001518860c001518960e001516040518863ffffffff1660e01b815260040161258c979695949392919061594d565b6020604051808303816000875af11580156125ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125cf919061598d565b80855260608301516001600160a01b03908116602087015260e084015116604086015260000361264d57600d5460ff16156126485760405162461bcd60e51b8152602060048201526019602482015278556e6966696564526f7574657256323a20736c69707061676560381b6044820152606401610293565b600292505b505061297f565b604051602960f91b60208201528890602101604051602081830303815290604052805190602001200361276e576000868060200190518101906126979190615930565b905060006126a88260800151613892565b90506126c2826020015183604001518460e001518761390d565b6001600160a01b0390811660e0860181905291166040850152602084019190915260608301516126f391468c613a21565b6001600160a01b0316606083015281516040830151602084015161271a9291908490613b41565b806001600160a01b031663cd7bfd5883600001518460200151856060015186608001518760a001518860c001518960e001516040518863ffffffff1660e01b815260040161258c979695949392919061594d565b604051605360f81b60208201528890602101604051602081830303815290604052805190602001200361297b576000868060200190518101906127b191906159a6565b905060006127c28260800151613892565b90506127dd826020015183604001518461010001518761390d565b6001600160a01b039081166101008601819052911660408501526020840191909152606083015161280f91468c613a21565b6001600160a01b031660608301528151604083015160208401516128369291908490613b41565b815160208301516060840151608085015160a086015160c087015160e0880151610100890151604051636469c44f60e01b81526001600160a01b039889166004820152602481019790975294871660448701529286166064860152608485019190915260ff90811660a48501521660c4830152821660e482015290821690636469c44f90610104016020604051808303816000875af11580156128dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612901919061598d565b80855260608301516001600160a01b03908116602087015261010084015116604086015260000361264d57600d5460ff16156126485760405162461bcd60e51b8152602060048201526019602482015278556e6966696564526f7574657256323a20736c69707061676560381b6044820152606401610293565b5060005b95509550955095915050565b60048054604080516345d61ded60e01b8152905160009384936001600160a01b0316926345d61ded92818301926020928290030181865afa1580156129d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f89190615265565b90506000816001600160a01b031663d087d2886040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a5e919061598d565b60408051306020808301919091528183018490526001600160401b03881660608301524660808301526001600160a01b03891660a0808401919091528351808403909101815260c090920190925280519101209091505b95945050505050565b600060ff8216601f8111156107ce57604051632cd44ac360e21b815260040160405180910390fd5b6001600160a01b03811660009081526007602052604090208054600181018255905b50919050565b60006107ce612b1b613b6d565b8360405161190160f01b8152600281019290925260228201526042902090565b6000806000612b4c87878787613c9d565b91509150612b5981613d61565b5090505b949350505050565b604080516060818101835260008083526020830181905292820183905290604051600560fc1b602082015260019088906021016040516020818303038152906040528051906020012003612d8857600b5415612c035760405162461bcd60e51b815260206004820152601a60248201527f526f757465723a207065726d6974206e6f7420616c6c6f7765640000000000006044820152606401610293565b600086806020019051810190612c199190615a4e565b805160208201516040808401516060850151608086015160a087015160c0880151945163d505accf60e01b81526001600160a01b0396871660048201523060248201526044810194909452606484019290925260ff16608483015260a482015260c4810191909152929350169063d505accf9060e401600060405180830381600087803b158015612ca957600080fd5b505af1925050508015612cba575060015b612d8257604080820151825160208401519251636eb1769f60e11b81526001600160a01b0393841660048201523060248201529192169063dd62ed3e90604401602060405180830381865afa158015612d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d3b919061598d565b1015612d825760405162461bcd60e51b8152602060048201526016602482015275526f757465723a207065726d6974206661696c75726560501b6044820152606401610293565b5061297f565b604051614c4d60f01b60208201528890602201604051602081830303815290604052805190602001201480612de3575060405161425560f01b6020820152889060220160405160208183030381529060405280519060200120145b80612e14575060405161424d60f01b6020820152889060220160405160208183030381529060405280519060200120145b156134cc57600086806020019051810190612e2f9190615ace565b90508915156000036133a057612e53816020015182604001518360c001518961390d565b6001600160a01b0390811660c0850181905291166040840152602083019190915260608201516080830151612e8992908b613a21565b6001600160a01b03166060820152604051614c4d60f01b60208201526000908a906022016040516020818303038152906040528051906020012003612ed657612ed182613eab565b6131dd565b6004805460405163d4f0cceb60e01b81526001600160401b034616928101929092526000916001600160a01b039091169063d4f0cceb90602401602060405180830381865afa158015612f2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f519190615265565b83516040516305b338c160e21b81526001600160a01b0391821660048201529192508216906316cce30490602401602060405180830381865afa158015612f9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc09190615265565b91506001600160a01b0382161561301a57806001600160a01b031683604001516001600160a01b0316146130065761300683600001518460400151838660200151613fd5565b6001600160a01b0381166040840152613161565b60048054604080516393e59dc160e01b815290516001600160a01b039092169260009284926393e59dc192818101926020929091908290030181865afa158015613068573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061308c9190615265565b855160405163166dbc3760e21b81526001600160a01b039182166004820152919250600091908316906359b6f0dc90602401602060405180830381865afa1580156130db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ff9190615b65565b60ff16101561315a5760405162461bcd60e51b815260206004820152602160248201527f526f757465723a2073796e7468206d7573742062652077686974656c697374656044820152601960fa1b6064820152608401610293565b5050825191505b806001600160a01b031663b6ff156a846000015185602001518660400151876060015188608001516040518663ffffffff1660e01b81526004016131a9959493929190615b82565b600060405180830381600087803b1580156131c357600080fd5b505af11580156131d7573d6000803e3d6000fd5b50505050505b81608001519550896040516020016131fd90614c4d60f01b815260020190565b6040516020818303038152906040528051906020012014613303576000819050806001600160a01b0316630e7c1cb56040518163ffffffff1660e01b8152600401602060405180830381865afa15801561325b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061327f9190615265565b6001600160a01b039081168452604080516306ed82dd60e31b815290519183169163376c16e8916004808201926020929091908290030181865afa1580156132cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132ef9190615bbd565b6001600160401b031660a084015250613313565b6001600160401b03461660a08301525b81604051602001613389919081516001600160a01b039081168252602080840151908301526040808401518216908301526060808401518216908301526080808401516001600160401b039081169184019190915260a0848101519091169083015260c092830151169181019190915260e00190565b604051602081830303815290604052945050612d82565b6009546000908152600f602052604081205460ff1660028111156133c6576133c66151df565b1461340a5760405162461bcd60e51b8152602060048201526014602482015273149bdd5d195c8e881bdc081c1c9bd8d95cdcd95960621b6044820152606401610293565b6009546000908152600f60205260409020805460ff1916600117905560608101516001600160a01b031661345f5761345081606001518260c0015183608001518b613a21565b6001600160a01b031660608201525b60405161425560f01b60208201528990602201604051602081830303815290604052805190602001201461349b5761349681614040565b6134a4565b6134a481614147565b835260608101516001600160a01b03908116602085015260c08201511660408401525061297f565b604051605760f81b60208201528890602101604051602081830303815290604052805190602001201480613526575060405161557760f01b6020820152889060220160405160208183030381529060405280519060200120145b15613601576000868060200190518101906135419190615bda565b9050600061355a8260200151836040015160008a61390d565b6001600160a01b039091166040850152602084019190915260608301519091506135869080468c613a21565b6001600160a01b03166060830152604051605760f81b60208201528a9060210160405160208183030381529060405280519060200120146135cf576135ca82614205565b6135d8565b6135d8826143ae565b845250606001516001600160a01b0390811660208401526040868101519091169083015261297f565b60405161214d60f01b6020820152889060220160405160208183030381529060405280519060200120148061365c575060405161215560f01b6020820152889060220160405160208183030381529060405280519060200120145b15613880576000868060200190518101906136779190615c55565b905089151560000361371657600181516000908152600f602052604090205460ff1660028111156136aa576136aa6151df565b036136ee5760405162461bcd60e51b8152602060048201526014602482015273149bdd5d195c8e881bdc081c1c9bd8d95cdcd95960621b6044820152606401610293565b80516000908152600f60209081526040909120805460ff191660021790558101519450612d82565b80516000908152600860205260408120805461373190615226565b80601f016020809104026020016040519081016040528092919081815260200182805461375d90615226565b80156137aa5780601f1061377f576101008083540402835291602001916137aa565b820191906000526020600020905b81548152906001019060200180831161378d57829003601f168201915b5050505050905080516000036137fb5760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881bdc081b9bdd081cdd185c9d195960521b6044820152606401610293565b6000818060200190518101906138119190615ace565b8351600090815260086020526040812091925061382e9190614c55565b60405161214d60f01b60208201528b90602201604051602081830303815290604052805190602001200361386c57613865816144ca565b8552613878565b613875816145ed565b85525b50505061297f565b50839050600095509550955095915050565b6001600160a01b0380821660009081526011602052604090205416806139085760405162461bcd60e51b815260206004820152602560248201527f556e6966696564526f7574657256323a20706f6f6c2061646170746572206e6f6044820152641d081cd95d60da1b6064820152608401610293565b919050565b600080600060001987146139215786613924565b83515b92506001600160a01b0386161561398c576001600160a01b03861633146139845760405162461bcd60e51b81526020600482015260146024820152732937baba32b91d103bb937b7339039b2b73232b960611b6044820152606401610293565b859150613994565b836020015191505b6009541580156139ac57506001600160a01b03851615155b15613a10576001600160a01b0385163314613a095760405162461bcd60e51b815260206004820152601960248201527f526f757465723a2077726f6e6720656d657267656e6379546f000000000000006044820152606401610293565b5083613a17565b5060408301515b9450945094915050565b6000613a2f85858585614797565b90506001600160a01b038116612b5d57604051604160f81b602082015260210160405160208183030381529060405280519060200120821480613a965750604051602960f91b60208201526021016040516020818303038152906040528051906020012082145b80613ac55750604051605360f81b60208201526021016040516020818303038152906040528051906020012082145b15612b5d576004805460405163687f4b5760e11b81526001600160401b038616928101929092526001600160a01b03169063d0fe96ae906024015b602060405180830381865afa158015613b1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab59190615265565b306001600160a01b03841603613b6157613b5c848383614a2d565b610e96565b610e9684848484613fd5565b6000306001600160a01b037f000000000000000000000000a2a786ff9148f7c88ee93372db8cbe9e94585c7416148015613bc657507f00000000000000000000000000000000000000000000000000000000000000fa46145b15613bf057507f4c32f8f3bdaae47bb966d8d294a011e34a4f8c4b684adbcdce8e52a07fa46cb490565b613c98604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527fc2a59fd4499513f5d074d325c5dcf8b1f005e4fbb0493c56f92b05b38e5d3b25918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613cd45750600090506003613d58565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613d28573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613d5157600060019250925050613d58565b9150600090505b94509492505050565b6000816004811115613d7557613d756151df565b03613d7d5750565b6001816004811115613d9157613d916151df565b03613dde5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610293565b6002816004811115613df257613df26151df565b03613e3f5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610293565b6003816004811115613e5357613e536151df565b0361090e5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610293565b60048054604051630f5427af60e41b81526001600160401b034616928101929092526000916001600160a01b039091169063f5427af090602401602060405180830381865afa158015613f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f269190615265565b9050806001600160a01b031682604001516001600160a01b031614613f5d57613f5d82600001518360400151838560200151613fd5565b806001600160a01b0316633fea56b883600001518460200151856040015186606001516040518563ffffffff1660e01b8152600401613f9f9493929190615caa565b600060405180830381600087803b158015613fb957600080fd5b505af1158015613fcd573d6000803e3d6000fd5b505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052610e969085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614a5d565b6004805460405163d4f0cceb60e01b81526001600160401b0346169281019290925260009182916001600160a01b03169063d4f0cceb90602401602060405180830381865afa158015614097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140bb9190615265565b83516020850151604080870151606088015160a0890151925163df543e8160e01b81529596506001600160a01b0387169563df543e819561410495909490939291600401615b82565b6020604051808303816000875af1158015614123573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc0919061598d565b60048054604051630f5427af60e41b81526001600160401b0346169281019290925260009182916001600160a01b03169063f5427af090602401602060405180830381865afa15801561419e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c29190615265565b8351602085015160408087015160608801519151637f27a5b960e11b81529495506001600160a01b0386169463fe4f4b7294614104949093909291600401615caa565b60006001600c54614216919061541d565b600b54146142665760405162461bcd60e51b815260206004820152601a60248201527f526f757465723a20756e77726170206e6f7420616c6c6f7765640000000000006044820152606401610293565b60408201516001600160a01b031630146142925761429282600001518360400151308560200151613fd5565b81516020830151604051632e1a7d4d60e01b81526001600160a01b0390921691632e1a7d4d916142c89160040190815260200190565b600060405180830381600087803b1580156142e257600080fd5b505af11580156142f6573d6000803e3d6000fd5b50505050600082606001516001600160a01b0316836020015160405160006040518083038185875af1925050503d806000811461434f576040519150601f19603f3d011682016040523d82523d6000602084013e614354565b606091505b50509050806143a55760405162461bcd60e51b815260206004820152601a60248201527f526f757465723a206661696c656420746f2073656e64204554480000000000006044820152606401610293565b50506020015190565b6000600b546000146144025760405162461bcd60e51b815260206004820152601860248201527f526f757465723a2077726170206e6f7420616c6c6f77656400000000000000006044820152606401610293565b816020015134101561444f5760405162461bcd60e51b8152602060048201526016602482015275149bdd5d195c8e881a5b9d985b1a5908185b5bdd5b9d60521b6044820152606401610293565b81600001516001600160a01b031663d0e30db083602001516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561449257600080fd5b505af11580156144a6573d6000803e3d6000fd5b50505050506144c2826000015183606001518460200151614a2d565b506020015190565b6080810151600a546000916001600160401b0391821691161461452f5760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a2077726f6e6720656d657267656e637920696e6974000000006044820152606401610293565b60048054604051630f5427af60e41b81526001600160401b034616928101929092526000916001600160a01b039091169063f5427af090602401602060405180830381865afa158015614586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145aa9190615265565b8351602085015160408087015160c0880151915163c26b5bab60e01b81529495506001600160a01b0386169463c26b5bab94614104949093909291600401615caa565b6080810151600a546000916001600160401b039182169116146146525760405162461bcd60e51b815260206004820152601c60248201527f526f757465723a2077726f6e6720656d657267656e637920696e6974000000006044820152606401610293565b6004805460405163d4f0cceb60e01b81526001600160401b034616928101929092526000916001600160a01b039091169063d4f0cceb90602401602060405180830381865afa1580156146a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146cd9190615265565b60a08401518451604051637f9fa89f60e01b81526001600160401b0390921660048301526001600160a01b03908116602483015291925090821690637f9fa89f90604401602060405180830381865afa15801561472e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147529190615265565b6001600160a01b03908116808552602085015160408087015160c0880151915163550bf7db60e11b81529486169463aa17efb694614104949093909291600401615caa565b60006001600160a01b03851615806147ad575081155b6147ec5760405162461bcd60e51b815260206004820152601060248201526f526f757465723a2077726f6e6720746f60801b6044820152606401610293565b8161485357849050836001600160a01b0316816001600160a01b03161461484e5760405162461bcd60e51b81526020600482015260166024820152752937baba32b91d103bb937b733903932b1b2b4bb32b960511b6044820152606401610293565b612b5d565b604051614c4d60f01b60208201526022016040516020818303038152906040528051906020012082036148fe5760048054604051630f5427af60e41b81526001600160401b038616928101929092526001600160a01b03169063f5427af0906024015b602060405180830381865afa1580156148d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f79190615265565b9050612b5d565b60405161425560f01b602082015260220160405160208183030381529060405280519060200120821480614957575060405161424d60f01b60208201526022016040516020818303038152906040528051906020012082145b15614996576004805460405163d4f0cceb60e01b81526001600160401b038616928101929092526001600160a01b03169063d4f0cceb906024016148b6565b604051605760f81b60208201528290602101604051602081830303815290604052805190602001201480613ac5575060405161557760f01b602082015282906022016040516020818303038152906040528051906020012003612b5d576004805460405163687f4b5760e11b81526001600160401b038616928101929092526001600160a01b03169063d0fe96ae90602401613b00565b6040516001600160a01b03831660248201526044810182905261087c90849063a9059cbb60e01b90606401614009565b6000614ab2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614b329092919063ffffffff16565b9050805160001480614ad3575080806020019051810190614ad39190615430565b61087c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610293565b6060612b5d848460008585600080866001600160a01b03168587604051614b599190615cd5565b60006040518083038185875af1925050503d8060008114614b96576040519150601f19603f3d011682016040523d82523d6000602084013e614b9b565b606091505b5091509150614bac87838387614bb7565b979650505050505050565b60608315614c26578251600003614c1f576001600160a01b0385163b614c1f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610293565b5081612b5d565b612b5d8383815115614c3b5781518083602001fd5b8060405162461bcd60e51b81526004016102939190614da1565b508054614c6190615226565b6000825580601f10614c71575050565b601f01602090049060005260206000209081019061090e91905b80821115614c9f5760008155600101614c8b565b5090565b80356001600160e01b03198116811461390857600080fd5b600060208284031215614ccd57600080fd5b610bc082614ca3565b6001600160a01b038116811461090e57600080fd5b600060208284031215614cfd57600080fd5b8135610bc081614cd6565b600060208284031215614d1a57600080fd5b5035919050565b60008060408385031215614d3457600080fd5b823591506020830135614d4681614cd6565b809150509250929050565b60005b83811015614d6c578181015183820152602001614d54565b50506000910152565b60008151808452614d8d816020860160208601614d51565b601f01601f19169290920160200192915050565b602081526000610bc06020830184614d75565b60ff8116811461090e57600080fd5b60008083601f840112614dd557600080fd5b5081356001600160401b03811115614dec57600080fd5b6020830191508360208260051b8501011115614e0757600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b0381118282101715614e4757614e47614e0e565b60405290565b60405160e081016001600160401b0381118282101715614e4757614e47614e0e565b604051601f8201601f191681016001600160401b0381118282101715614e9757614e97614e0e565b604052919050565b6000601f8381840112614eb157600080fd5b823560206001600160401b0380831115614ecd57614ecd614e0e565b8260051b614edc838201614e6f565b9384528681018301938381019089861115614ef657600080fd5b84890192505b85831015614f8657823584811115614f145760008081fd5b8901603f81018b13614f265760008081fd5b85810135604086821115614f3c57614f3c614e0e565b614f4d828b01601f19168901614e6f565b8281528d82848601011115614f625760008081fd5b828285018a8301376000928101890192909252508352509184019190840190614efc565b9998505050505050505050565b600080600080600060808688031215614fab57600080fd5b853594506020860135614fbd81614db4565b935060408601356001600160401b0380821115614fd957600080fd5b614fe589838a01614dc3565b90955093506060880135915080821115614ffe57600080fd5b5061500b88828901614e9f565b9150509295509295909350565b60ff60f81b881681526000602060e08184015261503860e084018a614d75565b838103604085015261504a818a614d75565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b8181101561509c57835183529284019291840191600101615080565b50909c9b505050505050505050505050565b600080604083850312156150c157600080fd5b50508035926020909101359150565b6001600160401b038116811461090e57600080fd5b6000806000606084860312156150fa57600080fd5b61510384614ca3565b9250602084013561511381614cd6565b91506040840135615123816150d0565b809150509250925092565b60008060008084860360e081121561514557600080fd5b85356001600160401b038082111561515c57600080fd5b61516889838a01614dc3565b9097509550602088013591508082111561518157600080fd5b5061518e88828901614e9f565b93505060a0603f19820112156151a357600080fd5b509295919450926040019150565b600080604083850312156151c457600080fd5b82356151cf81614cd6565b91506020830135614d4681614cd6565b634e487b7160e01b600052602160045260246000fd5b6003811061090e57634e487b7160e01b600052602160045260246000fd5b60208101615220836151f5565b91905290565b600181811c9082168061523a57607f821691505b602082108103612b0857634e487b7160e01b600052602260045260246000fd5b805161390881614cd6565b60006020828403121561527757600080fd5b8151610bc081614cd6565b601f82111561087c57600081815260208120601f850160051c810160208610156152a95750805b601f850160051c820191505b81811015613fcd578281556001016152b5565b81516001600160401b038111156152e1576152e1614e0e565b6152f5816152ef8454615226565b84615282565b602080601f83116001811461532a57600084156153125750858301515b600019600386901b1c1916600185901b178555613fcd565b600085815260208120601f198616915b828110156153595788860151825594840194600190910190840161533a565b50858210156153775787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60208082526018908201527f42617365526f757465723a2077726f6e6720706172616d730000000000000000604082015260600190565b6001600160401b03878116825260208201879052851660408201526060810184905260c081016153ed846151f5565b83608083015260ff831660a0830152979650505050505050565b634e487b7160e01b600052601160045260246000fd5b818103818111156107ce576107ce615407565b60006020828403121561544257600080fd5b81518015158114610bc057600080fd5b80516020808301519190811015612b085760001960209190910360031b1b16919050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516154ae816017850160208801614d51565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516154df816028840160208801614d51565b01602801949350505050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261551857600080fd5b8301803591506001600160401b0382111561553257600080fd5b602001915036819003821315614e0757600080fd5b8183823760009101908152919050565b808201808211156107ce576107ce615407565b6a02937baba32b91d1037b8160ad1b81528183600b83013770081a5cc81b9bdd081cdd5c1c1bdc9d1959607a1b9101600b810191909152601c01919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526020808501808196508360051b8101915082860160005b8581101561561a578284038952615608848351614d75565b988501989350908401906001016155f0565b5091979650505050505050565b600060808201878352602060ff881681850152608060408501528186835260a08501905060a08760051b86010192508760005b888110156156c957868503609f190183528135368b9003601e1901811261568057600080fd5b8a0184810190356001600160401b0381111561569b57600080fd5b8036038213156156aa57600080fd5b6156b58782846155a9565b96505050918301919083019060010161565a565b5050505082810360608401526156df81856155d2565b98975050505050505050565b6080815260006156fe6080830187614d75565b6001600160a01b0395861660208401526001600160401b03949094166040830152509216606090920191909152919050565b60006001820161574257615742615407565b5060010190565b6000845161575b818460208901614d51565b8201838582376000930192835250909392505050565b60008351615783818460208801614d51565b600b60fa1b90830190815283516157a1816001840160208801614d51565b01600101949350505050565b8781526bffffffffffffffffffffffff198760601b166020820152856034820152846054820152600084516157e9816074850160208901614d51565b909101607481019390935250609482015260b40195945050505050565b60006020828403121561581857600080fd5b8135610bc081614db4565b80820281158282048414176107ce576107ce615407565b60008161584957615849615407565b506000190190565b634e487b7160e01b600052603160045260246000fd5b805161390881614db4565b600061010080838503121561588657600080fd5b604051908101906001600160401b03821181831017156158a8576158a8614e0e565b81604052809250835191506158bc82614cd6565b818152602084015160208201526158d56040850161525a565b60408201526158e66060850161525a565b60608201526158f76080850161525a565b608082015260a084015160a082015261591260c08501615867565b60c082015261592360e0850161525a565b60e0820152505092915050565b6000610100828403121561594357600080fd5b610bc08383615872565b6001600160a01b039788168152602081019690965293861660408601529185166060850152608084015260ff1660a083015290911660c082015260e00190565b60006020828403121561599f57600080fd5b5051919050565b600061012082840312156159b957600080fd5b6159c1614e24565b6159ca8361525a565b8152602083015160208201526159e26040840161525a565b60408201526159f36060840161525a565b6060820152615a046080840161525a565b608082015260a083015160a0820152615a1f60c08401615867565b60c0820152615a3060e08401615867565b60e0820152610100615a4381850161525a565b908201529392505050565b600060e08284031215615a6057600080fd5b615a68614e4d565b8251615a7381614cd6565b81526020830151615a8381614cd6565b8060208301525060408301516040820152606083015160608201526080830151615aac81614db4565b608082015260a0838101519082015260c0928301519281019290925250919050565b600060e08284031215615ae057600080fd5b615ae8614e4d565b8251615af381614cd6565b8152602083810151908201526040830151615b0d81614cd6565b60408201526060830151615b2081614cd6565b60608201526080830151615b33816150d0565b608082015260a0830151615b46816150d0565b60a082015260c0830151615b5981614cd6565b60c08201529392505050565b600060208284031215615b7757600080fd5b8151610bc081614db4565b6001600160a01b0395861681526020810194909452918416604084015290921660608201526001600160401b03909116608082015260a00190565b600060208284031215615bcf57600080fd5b8151610bc0816150d0565b600060808284031215615bec57600080fd5b604051608081018181106001600160401b0382111715615c0e57615c0e614e0e565b6040528251615c1c81614cd6565b8152602083810151908201526040830151615c3681614cd6565b60408201526060830151615c4981614cd6565b60608201529392505050565b600060408284031215615c6757600080fd5b604051604081018181106001600160401b0382111715615c8957615c89614e0e565b604052825181526020830151615c9e816150d0565b60208201529392505050565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b60008251615ce7818460208701614d51565b919091019291505056fea26469706673582212205776d4f17c3c44a385839b60318559289acc63e8147e482d5e9619bd852ff16864736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000009bbc7661af64d7af74f41ffee71a2b2798900d31
-----Decoded View---------------
Arg [0] : addressBook_ (address): 0x9BbC7661af64d7af74F41FfEE71a2b2798900d31
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000009bbc7661af64d7af74f41ffee71a2b2798900d31
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
SCROLL | 100.00% | $3,921.3 | 0.00501211 | $19.65 |
[ 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.