Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- L2CrossTrade
- Optimization enabled
- true
- Compiler version
- v0.8.24+commit.e11b9ed9
- Optimization runs
- 100000000
- EVM Version
- paris
- Verified at
- 2024-08-19T10:17:14.796762Z
contracts/L2/L2CrossTrade.sol
// SPDX-License-Identifier: Unlicense pragma solidity 0.8.24; import "../libraries/SafeERC20.sol"; import "../proxy/ProxyStorage.sol"; import { AccessibleCommon } from "../common/AccessibleCommon.sol"; import { L2CrossTradeStorage } from "./L2CrossTradeStorage.sol"; import { IOptimismMintableERC20, ILegacyMintableERC20 } from "../interfaces/IOptimismMintableERC20.sol"; import { IL2CrossDomainMessenger } from "../interfaces/IL2CrossDomainMessenger.sol"; import { ReentrancyGuard } from "../utils/ReentrancyGuard.sol"; // import "hardhat/console.sol"; contract L2CrossTrade is ProxyStorage, AccessibleCommon, L2CrossTradeStorage, ReentrancyGuard { using SafeERC20 for IERC20; event RequestCT( address _l1token, address _l2token, address _requester, uint256 _totalAmount, uint256 _ctAmount, uint256 indexed _saleCount, uint256 _l2chainId, bytes32 _hashValue ); event NonRequestCT( address _l1token, address _l2token, address _requester, uint256 _totalAmount, uint256 _ctAmount, uint256 indexed _saleCount, uint256 _l2chainId, bytes32 _hashValue ); event ProviderClaimCT( address _l1token, address _l2token, address _requester, address _provider, uint256 _totalAmount, uint256 _ctAmount, uint256 indexed _saleCount, uint256 _l2chainId, bytes32 _hash ); event CancelCT( address _requester, uint256 _totalAmount, uint256 indexed _saleCount, uint256 _l2chainId, bytes32 _hash ); // event EditCT( // address _requester, // uint256 _ctAmount, // uint256 indexed _saleCount // ); //=======modifier======== modifier onlyEOA() { require(msg.sender == tx.origin, "L2FW: function can only be called from an EOA"); _; } modifier checkL1(uint256 _chainId) { require( msg.sender == address(crossDomainMessenger) && IL2CrossDomainMessenger(crossDomainMessenger).xDomainMessageSender() == chainData[_chainId].l1CrossTradeContract, "only call l1FastWithdraw" ); _; } modifier providerCheck(uint256 _saleCount) { require(dealData[_saleCount].provider == address(0), "already sold"); _; } modifier nonZero(uint256 _amount) { require(_amount > 0 , "input amount need nonZero"); _; } // modifier nonZeroAddr(address _addr) { // require(_addr != address(0) , "nonZeroAddr"); // _; // } //=======external======== /// @notice Register L1token and L2token and use them in requestRegisteredToken /// @param _l1token l1token Address /// @param _l2token l2token Address /// @param _l1chainId chainId of l1token function registerToken( address _l1token, address _l2token, uint256 _l1chainId ) external onlyOwner { require(registerCheck[_l1chainId][_l1token][_l2token] == false, "already registerToken"); registerCheck[_l1chainId][_l1token][_l2token] = true; } /// @notice Function to delete registered token /// @param _l1token l1token Address /// @param _l2token l2token Address /// @param _l1chainId chainId of l1token function deleteToken( address _l1token, address _l2token, uint256 _l1chainId ) external onlyOwner { require(registerCheck[_l1chainId][_l1token][_l2token] != false, "already deleteToken"); registerCheck[_l1chainId][_l1token][_l2token] = false; } /// @notice Token transaction request registered in register /// @param _l1token l1token Address /// @param _l2token l2token Address /// @param _totalAmount Amount provided to L2 /// @param _ctAmount Amount to be received from L1 /// @param _l1chainId chainId of l1token function requestRegisteredToken( address _l1token, address _l2token, uint256 _totalAmount, uint256 _ctAmount, uint256 _l1chainId ) external payable onlyEOA nonZero(_totalAmount) nonZero(_ctAmount) nonReentrant { require(registerCheck[_l1chainId][_l1token][_l2token] == true, "not register token"); require(_totalAmount >= _ctAmount, "The totalAmount value must be greater than ctAmount"); unchecked { ++saleCount; } bytes32 hashValue = _request( _l1token, _l2token, _totalAmount, _ctAmount, saleCount, _l1chainId ); uint256 chainId = _getChainID(); emit RequestCT( _l1token, _l2token, msg.sender, _totalAmount, _ctAmount, saleCount, chainId, hashValue ); } /// @notice Token transaction request not registered in register /// @param _l1token l1token Address /// @param _l2token l2token Address /// @param _totalAmount Amount provided to L2 /// @param _ctAmount Amount to be received from L1 /// @param _l1chainId chainId of l1token function requestNonRegisteredToken( address _l1token, address _l2token, uint256 _totalAmount, uint256 _ctAmount, uint256 _l1chainId ) external payable onlyEOA nonZero(_totalAmount) nonZero(_ctAmount) nonReentrant { unchecked { ++saleCount; } bytes32 hashValue = _request( _l1token, _l2token, _totalAmount, _ctAmount, saleCount, _l1chainId ); uint256 chainId = _getChainID(); emit NonRequestCT( _l1token, _l2token, msg.sender, _totalAmount, _ctAmount, saleCount, chainId, hashValue ); } /// @notice When providing a function called from L1, the amount is given to the provider. /// @param _from provider Address /// @param _ctAmount Amount paid by L1 /// @param _saleCount Number generated upon request /// @param _chainId chainId of l1token /// @param _hash Hash value generated upon request function claimCT( address _from, uint256 _ctAmount, uint256 _saleCount, uint256 _chainId, bytes32 _hash ) external nonReentrant checkL1(_chainId) providerCheck(_saleCount) { require(dealData[_saleCount].hashValue == _hash, "Hash values do not match"); uint256 ctAmount = _ctAmount; if(_ctAmount == 0) { ctAmount = dealData[_saleCount].ctAmount; } dealData[_saleCount].provider = _from; address l2token = dealData[_saleCount].l2token; uint256 totalAmount = dealData[_saleCount].totalAmount; if(l2token == legacyERC20ETH) { (bool sent, ) = payable(_from).call{value: totalAmount}(""); require(sent, "claim fail"); } else { IERC20(l2token).safeTransfer(_from,totalAmount); } uint256 chainId = _getChainID(); emit ProviderClaimCT( dealData[_saleCount].l1token, l2token, dealData[_saleCount].requester, _from, totalAmount, ctAmount, _saleCount, chainId, _hash ); } /// @notice When canceling a function called from L1, the amount is given to the requester. /// @param _msgSender Address where cancellation was requested /// @param _salecount Number generated upon request /// @param _chainId chainId of l1token /// @param _hash Hash value generated upon request function cancelCT( address _msgSender, uint256 _salecount, uint256 _chainId, bytes32 _hash ) external nonReentrant checkL1(_chainId) providerCheck(_salecount) { require(dealData[_salecount].requester == _msgSender, "your not seller"); require(dealData[_salecount].hashValue == _hash, "Hash values do not match"); dealData[_salecount].provider = _msgSender; uint256 totalAmount = dealData[_salecount].totalAmount; if (dealData[_salecount].l2token == legacyERC20ETH) { (bool sent, ) = payable(_msgSender).call{value: totalAmount}(""); require(sent, "cancel refund fail"); } else { IERC20(dealData[_salecount].l2token).safeTransfer(_msgSender,totalAmount); } uint256 chainId = _getChainID(); emit CancelCT( _msgSender, totalAmount, _salecount, chainId, _hash ); } function claimOwnerCT( address _from, uint256 _ctAmount, uint256 _saleCount, uint256 _chainId, bytes32 _hash ) external onlyOwner nonReentrant providerCheck(_saleCount) { require(dealData[_saleCount].hashValue == _hash, "Hash values do not match"); uint256 ctAmount = _ctAmount; if(_ctAmount == 0) { ctAmount = dealData[_saleCount].ctAmount; } dealData[_saleCount].provider = _from; address l2token = dealData[_saleCount].l2token; uint256 totalAmount = dealData[_saleCount].totalAmount; if(l2token == legacyERC20ETH) { (bool sent, ) = payable(_from).call{value: totalAmount}(""); require(sent, "claim fail"); } else { IERC20(l2token).safeTransfer(_from,totalAmount); } uint256 chainId = _getChainID(); emit ProviderClaimCT( dealData[_saleCount].l1token, l2token, dealData[_saleCount].requester, _from, totalAmount, ctAmount, _saleCount, chainId, _hash ); } function cancelOwnerCT( address _msgSender, uint256 _salecount, uint256 _chainId, bytes32 _hash ) external onlyOwner nonReentrant providerCheck(_salecount) { require(dealData[_salecount].requester == _msgSender, "your not seller"); require(dealData[_salecount].hashValue == _hash, "Hash values do not match"); dealData[_salecount].provider = _msgSender; uint256 totalAmount = dealData[_salecount].totalAmount; if (dealData[_salecount].l2token == legacyERC20ETH) { (bool sent, ) = payable(_msgSender).call{value: totalAmount}(""); require(sent, "cancel refund fail"); } else { IERC20(dealData[_salecount].l2token).safeTransfer(_msgSender,totalAmount); } uint256 chainId = _getChainID(); emit CancelCT( _msgSender, totalAmount, _salecount, chainId, _hash ); } function checkModify( address _crossDomainMessenger, address _xDomainMessageSender, uint256 _chainId ) external view returns (uint256 modify) { if (_crossDomainMessenger != address(crossDomainMessenger)) { return modify = 1; } else if (_xDomainMessageSender != chainData[_chainId].l1CrossTradeContract) { return modify = 2; } return modify = 3; } /// @notice Function that calculates hash value in L2CrossTradeContract /// @param _l1token l1token Address /// @param _l2token l2token Address /// @param _requestor requester's address /// @param _totalAmount Amount provided to L2 /// @param _ctAmount Amount provided to L2 /// @param _saleCount Number generated upon request /// @param _startChainId The chainId where this contract was deployed /// @param _endChainId Destination chainID function getHash( address _l1token, address _l2token, address _requestor, uint256 _totalAmount, uint256 _ctAmount, uint256 _saleCount, uint256 _startChainId, uint256 _endChainId ) public pure returns (bytes32) { return keccak256( abi.encode( _l1token, _l2token, _requestor, _totalAmount, _ctAmount, _saleCount, _startChainId, _endChainId ) ); } // //=======Temporary view for testing ======== // function getChainID() public view returns (uint256 id) { // assembly { // id := chainid() // } // } //=======internal======== /// @notice Function to calculate l1token, l2token register hash value function _getChainID() private view returns (uint256 id) { assembly { id := chainid() } } /// @notice Token transaction request /// @param _l1token l1token Address /// @param _l2token l2token Address /// @param _totalAmount Amount provided to L2 /// @param _ctAmount Amount to be received from L1 /// @param _saleCount Number generated upon request /// @param _endChainId chainId of l1token function _request( address _l1token, address _l2token, uint256 _totalAmount, uint256 _ctAmount, uint256 _saleCount, uint256 _endChainId ) private returns (bytes32 hashValue) { if (_l2token == legacyERC20ETH) { require(msg.value == _totalAmount, "CT: nativeTON need amount"); } else { IERC20(_l2token).safeTransferFrom(msg.sender,address(this),_totalAmount); } uint256 startChainId = _getChainID(); hashValue = getHash( _l1token, _l2token, msg.sender, _totalAmount, _ctAmount, _saleCount, startChainId, _endChainId ); dealData[_saleCount] = RequestData({ l1token: _l1token, l2token: _l2token, requester: msg.sender, provider: address(0), totalAmount: _totalAmount, ctAmount: _ctAmount, chainId: _endChainId, hashValue: hashValue }); } }
@openzeppelin/contracts/utils/introspection/IERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @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); }
@openzeppelin/contracts/access/AccessControl.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "./IAccessControl.sol"; import {Context} from "../utils/Context.sol"; import {ERC165} from "../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 account => bool) hasRole; bytes32 adminRole; } mapping(bytes32 role => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ 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 returns (bool) { return _roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @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 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 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 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 `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @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 Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { if (!hasRole(role, account)) { _roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { if (hasRole(role, account)) { _roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
@openzeppelin/contracts/access/IAccessControl.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @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. */ 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 `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @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; } }
@openzeppelin/contracts/utils/introspection/ERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./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); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
contracts/L2/L2CrossTradeStorage.sol
// SPDX-License-Identifier: Unlicense pragma solidity 0.8.24; contract L2CrossTradeStorage { struct RequestData { address l1token; address l2token; address requester; address provider; uint256 totalAmount; uint256 ctAmount; uint256 chainId; bytes32 hashValue; } struct ChainIdData { address l1CrossTradeContract; address l1TON; } address public crossDomainMessenger; address public legacyERC20ETH; uint256 public saleCount; //saleCount => ChainData mapping(uint256 => RequestData) public dealData; mapping(uint256 => mapping(address => mapping(address => bool))) public registerCheck; //chainId => ChainData mapping(uint256 => ChainIdData) public chainData; }
contracts/common/AccessRoleCommon.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; contract AccessRoleCommon { bytes32 public constant ADMIN_ROLE = keccak256("ADMIN"); bytes32 public constant POLICY_ROLE = keccak256("POLICY_ROLE"); }
contracts/common/AccessibleCommon.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import "@openzeppelin/contracts/access/AccessControl.sol"; import "./AccessRoleCommon.sol"; contract AccessibleCommon is AccessRoleCommon, AccessControl { modifier onlyOwner() { require(isAdmin(msg.sender), "Accessible: Caller is not an admin"); _; } /// @dev add admin /// @param account address to add function addAdmin(address account) public virtual onlyOwner { grantRole(ADMIN_ROLE, account); } /// @dev remove admin /// @param account address to remove function removeAdmin(address account) public virtual onlyOwner { renounceRole(ADMIN_ROLE, account); } /// @dev transfer admin /// @param newAdmin new admin address function transferAdmin(address newAdmin) external virtual onlyOwner { require(newAdmin != address(0), "Accessible: zero address"); require(msg.sender != newAdmin, "Accessible: same admin"); grantRole(ADMIN_ROLE, newAdmin); renounceRole(ADMIN_ROLE, msg.sender); } /// @dev whether admin /// @param account address to check function isAdmin(address account) public view virtual returns (bool) { return hasRole(ADMIN_ROLE, account); } }
contracts/interfaces/IERC20.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); function mint(address account, uint256 amount) external returns (bool); function burn(address account, uint256 amount) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); }
contracts/interfaces/IL2CrossDomainMessenger.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IL2CrossDomainMessenger { function xDomainMessageSender() external view returns (address); }
contracts/interfaces/IOptimismMintableERC20.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /// @title IOptimismMintableERC20 /// @notice This interface is available on the OptimismMintableERC20 contract. /// We declare it as a separate interface so that it can be used in /// custom implementations of OptimismMintableERC20. interface IOptimismMintableERC20 is IERC165 { function remoteToken() external view returns (address); function bridge() external returns (address); function mint(address _to, uint256 _amount) external; function burn(address _from, uint256 _amount) external; } /// @custom:legacy /// @title ILegacyMintableERC20 /// @notice This interface was available on the legacy L2StandardERC20 contract. /// It remains available on the OptimismMintableERC20 contract for /// backwards compatibility. interface ILegacyMintableERC20 is IERC165 { function l1Token() external view returns (address); function mint(address _to, uint256 _amount) external; function burn(address _from, uint256 _amount) external; }
contracts/libraries/SafeERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.7.5; import {IERC20} from "../interfaces/IERC20.sol"; /// @notice Safe IERC20 and ETH transfer library that safely handles missing return values. /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/libraries/TransferHelper.sol) /// Taken from Solmate library SafeERC20 { function safeTransferFrom( IERC20 token, address from, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call( abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FROM_FAILED"); } function safeTransfer( IERC20 token, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call( abi.encodeWithSelector(IERC20.transfer.selector, to, amount) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FAILED"); } function safeApprove( IERC20 token, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call( abi.encodeWithSelector(IERC20.approve.selector, to, amount) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "APPROVE_FAILED"); } function safeTransferETH(address to, uint256 amount) internal { (bool success, ) = to.call{value: amount}(new bytes(0)); require(success, "ETH_TRANSFER_FAILED"); } }
contracts/proxy/ProxyStorage.sol
//SPDX-License-Identifier: Unlicense pragma solidity ^0.8.20; contract ProxyStorage { bool public pauseProxy; mapping(uint256 => address) public proxyImplementation; mapping(address => bool) public aliveImplementation; mapping(bytes4 => address) public selectorImplementation; }
contracts/utils/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @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 EIP-1153 (transient storage) is available on the chain you're deploying at, * consider using {ReentrancyGuardTransient} instead. * * 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; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); 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 if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // 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; } }
Compiler Settings
{"viaIR":true,"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":100000000,"enabled":true,"details":{"yul":true}},"libraries":{},"evmVersion":"paris"}
Contract ABI
[{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"bytes32","name":"neededRole","internalType":"bytes32"}]},{"type":"error","name":"ReentrancyGuardReentrantCall","inputs":[]},{"type":"event","name":"CancelCT","inputs":[{"type":"address","name":"_requester","internalType":"address","indexed":false},{"type":"uint256","name":"_totalAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"_saleCount","internalType":"uint256","indexed":true},{"type":"uint256","name":"_l2chainId","internalType":"uint256","indexed":false},{"type":"bytes32","name":"_hash","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"NonRequestCT","inputs":[{"type":"address","name":"_l1token","internalType":"address","indexed":false},{"type":"address","name":"_l2token","internalType":"address","indexed":false},{"type":"address","name":"_requester","internalType":"address","indexed":false},{"type":"uint256","name":"_totalAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"_ctAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"_saleCount","internalType":"uint256","indexed":true},{"type":"uint256","name":"_l2chainId","internalType":"uint256","indexed":false},{"type":"bytes32","name":"_hashValue","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"ProviderClaimCT","inputs":[{"type":"address","name":"_l1token","internalType":"address","indexed":false},{"type":"address","name":"_l2token","internalType":"address","indexed":false},{"type":"address","name":"_requester","internalType":"address","indexed":false},{"type":"address","name":"_provider","internalType":"address","indexed":false},{"type":"uint256","name":"_totalAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"_ctAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"_saleCount","internalType":"uint256","indexed":true},{"type":"uint256","name":"_l2chainId","internalType":"uint256","indexed":false},{"type":"bytes32","name":"_hash","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"RequestCT","inputs":[{"type":"address","name":"_l1token","internalType":"address","indexed":false},{"type":"address","name":"_l2token","internalType":"address","indexed":false},{"type":"address","name":"_requester","internalType":"address","indexed":false},{"type":"uint256","name":"_totalAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"_ctAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"_saleCount","internalType":"uint256","indexed":true},{"type":"uint256","name":"_l2chainId","internalType":"uint256","indexed":false},{"type":"bytes32","name":"_hashValue","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"previousAdminRole","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"newAdminRole","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DEFAULT_ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"POLICY_ROLE","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addAdmin","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"aliveImplementation","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelCT","inputs":[{"type":"address","name":"_msgSender","internalType":"address"},{"type":"uint256","name":"_salecount","internalType":"uint256"},{"type":"uint256","name":"_chainId","internalType":"uint256"},{"type":"bytes32","name":"_hash","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelOwnerCT","inputs":[{"type":"address","name":"_msgSender","internalType":"address"},{"type":"uint256","name":"_salecount","internalType":"uint256"},{"type":"uint256","name":"_chainId","internalType":"uint256"},{"type":"bytes32","name":"_hash","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"l1CrossTradeContract","internalType":"address"},{"type":"address","name":"l1TON","internalType":"address"}],"name":"chainData","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"modify","internalType":"uint256"}],"name":"checkModify","inputs":[{"type":"address","name":"_crossDomainMessenger","internalType":"address"},{"type":"address","name":"_xDomainMessageSender","internalType":"address"},{"type":"uint256","name":"_chainId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimCT","inputs":[{"type":"address","name":"_from","internalType":"address"},{"type":"uint256","name":"_ctAmount","internalType":"uint256"},{"type":"uint256","name":"_saleCount","internalType":"uint256"},{"type":"uint256","name":"_chainId","internalType":"uint256"},{"type":"bytes32","name":"_hash","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimOwnerCT","inputs":[{"type":"address","name":"_from","internalType":"address"},{"type":"uint256","name":"_ctAmount","internalType":"uint256"},{"type":"uint256","name":"_saleCount","internalType":"uint256"},{"type":"uint256","name":"_chainId","internalType":"uint256"},{"type":"bytes32","name":"_hash","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"crossDomainMessenger","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"l1token","internalType":"address"},{"type":"address","name":"l2token","internalType":"address"},{"type":"address","name":"requester","internalType":"address"},{"type":"address","name":"provider","internalType":"address"},{"type":"uint256","name":"totalAmount","internalType":"uint256"},{"type":"uint256","name":"ctAmount","internalType":"uint256"},{"type":"uint256","name":"chainId","internalType":"uint256"},{"type":"bytes32","name":"hashValue","internalType":"bytes32"}],"name":"dealData","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deleteToken","inputs":[{"type":"address","name":"_l1token","internalType":"address"},{"type":"address","name":"_l2token","internalType":"address"},{"type":"uint256","name":"_l1chainId","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getHash","inputs":[{"type":"address","name":"_l1token","internalType":"address"},{"type":"address","name":"_l2token","internalType":"address"},{"type":"address","name":"_requestor","internalType":"address"},{"type":"uint256","name":"_totalAmount","internalType":"uint256"},{"type":"uint256","name":"_ctAmount","internalType":"uint256"},{"type":"uint256","name":"_saleCount","internalType":"uint256"},{"type":"uint256","name":"_startChainId","internalType":"uint256"},{"type":"uint256","name":"_endChainId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRoleAdmin","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isAdmin","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"legacyERC20ETH","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"pauseProxy","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"proxyImplementation","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"registerCheck","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"registerToken","inputs":[{"type":"address","name":"_l1token","internalType":"address"},{"type":"address","name":"_l2token","internalType":"address"},{"type":"uint256","name":"_l1chainId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeAdmin","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"callerConfirmation","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"requestNonRegisteredToken","inputs":[{"type":"address","name":"_l1token","internalType":"address"},{"type":"address","name":"_l2token","internalType":"address"},{"type":"uint256","name":"_totalAmount","internalType":"uint256"},{"type":"uint256","name":"_ctAmount","internalType":"uint256"},{"type":"uint256","name":"_l1chainId","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"requestRegisteredToken","inputs":[{"type":"address","name":"_l1token","internalType":"address"},{"type":"address","name":"_l2token","internalType":"address"},{"type":"uint256","name":"_totalAmount","internalType":"uint256"},{"type":"uint256","name":"_ctAmount","internalType":"uint256"},{"type":"uint256","name":"_l1chainId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"saleCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"selectorImplementation","inputs":[{"type":"bytes4","name":"","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferAdmin","inputs":[{"type":"address","name":"newAdmin","internalType":"address"}]}]
Contract Creation Code
0x6080806040523461001b576001600b556126c590816100218239f35b600080fdfe608060408181526004908136101561001657600080fd5b600092833560e01c90816301ffc9a7146117c5575080630f377395146116ce57806316019f4d1461164057806316e01724146115ed5780631785f53c146115725780632298524614611519578063248a9ca3146114d157806324d7806c146114415780632f2ff15d146113f857806336568abe1461136d57806350d2a276146112e7578063550d01a3146112805780635988ec501461101857806363a8fd8914610fd85780637048027514610f4757806375829def14610dc657806375b238fc14610d6d57806381f331da14610bc75780638800867b14610b435780638a020c6714610ad957806391d1485414610a695780639792f8d714610938578063a1e89aec146108fb578063a217fddf146108c2578063b6f7134b1461078f578063b911135f14610733578063cd4618af14610710578063d547741f146106b3578063ddf0cbf4146105e1578063e59f69c214610579578063f43b361314610522578063f5869c2f146104665763fc9dc1861461018f57600080fd5b346104625761019d3661194d565b929391946101a9611f2d565b8073ffffffffffffffffffffffffffffffffffffffff9283600554169081331491826103c9575b50506101dc9150611b0a565b858752602090600882526101f8836003868b2001541615611b6f565b86885260088252826002858a200154169583811680970361036d578789526008835261022b866007878c20015414611bd4565b878952600883528489209360038501887fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580600184870154960154169060065416811460001461033357505087808080868a5af161028d611c39565b50156102d8575091608093917f62d1466ea7dfd1b476db9e90a17828c8bb0fc5a57df551bf584a7f8a354878b495935b825194855284015246908301526060820152a26001600b5580f35b6064918451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601260248201527f63616e63656c20726566756e64206661696c00000000000000000000000000006044820152fd5b846080979593507f62d1466ea7dfd1b476db9e90a17828c8bb0fc5a57df551bf584a7f8a354878b49896949261036892611f80565b6102bd565b506064918451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f796f7572206e6f742073656c6c657200000000000000000000000000000000006044820152fd5b60209192508651938480927f6e296e450000000000000000000000000000000000000000000000000000000082525afa91821561045857906101dc92918a92610427575b508952600a6020528380868b2054169116148291386101d0565b61044a91925060203d602011610451575b6104428183611a6e565b810190611ade565b903861040d565b503d610438565b85513d8b823e3d90fd5b8280fd5b50823461051f5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261051f5782358152600860209081529082902080546001820154600283015460038401549684015460058501546006860154600790960154975173ffffffffffffffffffffffffffffffffffffffff9586168152938516968401969096529083166040830152919095166060860152608085015260a084019190915260c083015260e082015261010090f35b80fd5b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755760209073ffffffffffffffffffffffffffffffffffffffff600554169051908152f35b5080fd5b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257918192358152600a6020522073ffffffffffffffffffffffffffffffffffffffff6001818354169201541682519182526020820152f35b83827f9234c0bc9ec97c418266f9342cc42597ee66dc6f1c718161a25a8b8ba660d3e76106a8610656610613366119a6565b61062596949591939296323314611d75565b610630871515611e00565b61063b841515611e00565b610643611f2d565b60016007540180600755848885896123fa565b600754975173ffffffffffffffffffffffffffffffffffffffff9586168152919094166020820152336040820152606081019490945260808401524660a084015260c0830191909152819060e0820190565b0390a26001600b5580f35b50903461046257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104625761070c9161070760018335926106f76118aa565b948488526020528620015461209e565b612357565b5080f35b8382346105755760209061072c61072636611a0e565b91611edd565b9051908152f35b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610462578160209373ffffffffffffffffffffffffffffffffffffffff92358152600185522054169051908152f35b5090346104625761079f36611a0e565b7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec4286949392945260209280845285872033885284526107e360ff8789205416611c97565b818752600984528587209273ffffffffffffffffffffffffffffffffffffffff809116938489528552868820951694858852845260ff86882054166108665750855260098252838520908552815282842091845252812060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905580f35b606490848751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601560248201527f616c7265616479207265676973746572546f6b656e00000000000000000000006044820152fd5b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755751908152602090f35b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610575576020906007549051908152f35b5090346104625761094836611a0e565b7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42869493929452602092808452858720338852845261098c60ff8789205416611c97565b818752600984528587209273ffffffffffffffffffffffffffffffffffffffff809116938489528552868820951694858852845260ff868820541615610a0d575085526009825283852090855281528284209184525281207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905580f35b606490848751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601360248201527f616c72656164792064656c657465546f6b656e000000000000000000000000006044820152fd5b50903461046257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610462578160209360ff92610aa86118aa565b9080358352865273ffffffffffffffffffffffffffffffffffffffff83832091168252855220541690519015158152f35b838234610575576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755760209061072c610b19611882565b610b216118aa565b90610b2a6118cd565b60e4359260c4359260a435926084359260643592611e65565b5090346104625760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610462578160209360ff92610b836118aa565b610b8b6118cd565b913583526009875283832073ffffffffffffffffffffffffffffffffffffffff8092168452875283832091168252855220541690519015158152f35b508290610bd3366119a6565b9096610be494939294323314611d75565b610bef851515611e00565b610bfa881515611e00565b610c02611f2d565b818752600960205285872073ffffffffffffffffffffffffffffffffffffffff9081861689526020528688209084168852602052600160ff8789205416151503610d1057878510610c8d5750956106a8916106567f4ed7594528ea467b40aa40eeff1ebf7a53cd3771da17f533517dcd207b18b07796979860016007540180600755848885896123fa565b60849060208751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152603360248201527f54686520746f74616c416d6f756e742076616c7565206d75737420626520677260448201527f6561746572207468616e206374416d6f756e74000000000000000000000000006064820152fd5b60649060208751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601260248201527f6e6f7420726567697374657220746f6b656e00000000000000000000000000006044820152fd5b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057557602090517fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428152f35b5091903461057557602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257610e02611882565b917fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428085528282528585203386528252610e4160ff8787205416611c97565b73ffffffffffffffffffffffffffffffffffffffff84168015610eeb573314610e8f5794610e7d926001928697610e829752528520015461209e565b6120fb565b50610e8c33611d22565b80f35b606483838851917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601660248201527f41636365737369626c653a2073616d652061646d696e000000000000000000006044820152fd5b606484848951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601860248201527f41636365737369626c653a207a65726f206164647265737300000000000000006044820152fd5b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257610e7d600161070c93610f89611882565b937fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec4280885281602052828820338952602052610fca60ff848a205416611c97565b87526020528520015461209e565b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755760ff602092541690519015158152f35b5091903461057557611029366118f0565b969391949290507fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428652602092808452848720338852845261107060ff8689205416611c97565b611078611f2d565b8587526008845273ffffffffffffffffffffffffffffffffffffffff926110a7846003888b2001541615611b6f565b868852600885526110bf896007888b20015414611bd4565b821561126b575b8688526008855285882094600386019285831693847fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790558086600189015416970154938660065416881460001461122b578a80808781945af161112c611c39565b50156111d05750917ff8cde1fe2cd0b62a858b3e46ed74ad19f4de0483236632b75745d688c727af20979899939160086106a896945b8b8d5252878b20936002818654169501541697519788974695899491909360e096939998979461010087019a73ffffffffffffffffffffffffffffffffffffffff8094818094168a52166020890152166040870152166060850152608084015260a083015260c08201520152565b6064918851917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600a60248201527f636c61696d206661696c000000000000000000000000000000000000000000006044820152fd5b5050918160086106a89694611266847ff8cde1fe2cd0b62a858b3e46ed74ad19f4de0483236632b75745d688c727af209c9d9e98968b611f80565b611162565b868852600885528588206005015492506110c6565b8382346105755760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755760ff8160209373ffffffffffffffffffffffffffffffffffffffff6112d4611882565b1681526002855220541690519015158152f35b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257357fffffffff00000000000000000000000000000000000000000000000000000000811680910361046257818373ffffffffffffffffffffffffffffffffffffffff9260209552600385522054169051908152f35b5082903461057557807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610575576113a66118aa565b903373ffffffffffffffffffffffffffffffffffffffff8316036113d0575061070c919235612357565b8390517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b50903461046257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104625761070c9161143c60018335926106f76118aa565b6121d9565b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610462578160209360ff92611481611882565b907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428352865273ffffffffffffffffffffffffffffffffffffffff83832091168252855220541690519015158152f35b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257816020938260019335825285522001549051908152f35b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057557602090517ffb5864e8ff833c3cb2d2d08505e82ff02a43554c74a35d4f5a64e852612783118152f35b833461051f5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261051f57610e8c6115ad611882565b3360009081527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b6902260205260409020546115e89060ff16611c97565b611d22565b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755760209073ffffffffffffffffffffffffffffffffffffffff600654169051908152f35b50346104625761164f3661194d565b3360009081527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b69022602052604090205492959394909390929091506116959060ff16611c97565b61169d611f2d565b84865260206008815273ffffffffffffffffffffffffffffffffffffffff916101f8836003868b2001541615611b6f565b50919034610575576116df366118f0565b9693929091946116ed611f2d565b8073ffffffffffffffffffffffffffffffffffffffff93846005541690813314918261173c575b50506117209150611b0a565b858752602093600885526110a7846003888b2001541615611b6f565b60209192508851938480927f6e296e450000000000000000000000000000000000000000000000000000000082525afa9182156117bb579061172092918a9261179a575b508952600a6020528480888b205416911614829138611714565b6117b491925060203d602011610451576104428183611a6e565b9038611780565b87513d8b823e3d90fd5b849084346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257357fffffffff00000000000000000000000000000000000000000000000000000000811680910361046257602092507f7965db0b000000000000000000000000000000000000000000000000000000008114908115611858575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483611851565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036118a557565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff821682036118a557565b6044359073ffffffffffffffffffffffffffffffffffffffff821682036118a557565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a09101126118a55760043573ffffffffffffffffffffffffffffffffffffffff811681036118a5579060243590604435906064359060843590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60809101126118a55760043573ffffffffffffffffffffffffffffffffffffffff811681036118a55790602435906044359060643590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a09101126118a55773ffffffffffffffffffffffffffffffffffffffff9060043582811681036118a5579160243590811681036118a55790604435906064359060843590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126118a55773ffffffffffffffffffffffffffffffffffffffff9060043582811681036118a5579160243590811681036118a5579060443590565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611aaf57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b908160209103126118a5575173ffffffffffffffffffffffffffffffffffffffff811681036118a55790565b15611b1157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6f6e6c792063616c6c206c3146617374576974686472617700000000000000006044820152fd5b15611b7657565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f616c726561647920736f6c6400000000000000000000000000000000000000006044820152fd5b15611bdb57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f486173682076616c75657320646f206e6f74206d6174636800000000000000006044820152fd5b3d15611c92573d9067ffffffffffffffff8211611aaf5760405191611c8660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611a6e565b82523d6000602084013e565b606090565b15611c9e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f41636365737369626c653a2043616c6c6572206973206e6f7420616e2061646d60448201527f696e0000000000000000000000000000000000000000000000000000000000006064820152fd5b3373ffffffffffffffffffffffffffffffffffffffff821603611d4b57611d4890612280565b50565b60046040517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b15611d7c57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f4c3246573a2066756e6374696f6e2063616e206f6e6c792062652063616c6c6560448201527f642066726f6d20616e20454f41000000000000000000000000000000000000006064820152fd5b15611e0757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e70757420616d6f756e74206e656564206e6f6e5a65726f000000000000006044820152fd5b969492909593919560405196602088019873ffffffffffffffffffffffffffffffffffffffff92838092168b52166040890152166060870152608086015260a085015260c084015260e083015261010090818301528152610120810181811067ffffffffffffffff821117611aaf5760405251902090565b600554919273ffffffffffffffffffffffffffffffffffffffff929091831690831614611f0c57505050600190565b600052600a6020528060406000205416911603611f2857600390565b600290565b6002600b5414611f3e576002600b55565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b908160209103126118a5575180151581036118a55790565b91909173ffffffffffffffffffffffffffffffffffffffff92604051928460208501927fa9059cbb0000000000000000000000000000000000000000000000000000000084521660248501526044840152604483526080830183811067ffffffffffffffff821117611aaf57600094859485926040525193165af1612003611c39565b8161206f575b501561201157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b8051801592508215612084575b505038612009565b6120979250602080918301019101611f68565b388061207c565b80600052600460205260406000203360005260205260ff60406000205416156120c45750565b604490604051907fe2517d3f0000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b73ffffffffffffffffffffffffffffffffffffffff1660008181527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b6902260205260408120549091907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec429060ff166121d4578083526004602052604083208284526020526040832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b505090565b90600091808352600460205273ffffffffffffffffffffffffffffffffffffffff6040842092169182845260205260ff604084205416156000146121d4578083526004602052604083208284526020526040832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b73ffffffffffffffffffffffffffffffffffffffff1660008181527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b6902260205260408120549091907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec429060ff16156121d457808352600460205260408320828452602052604083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b90600091808352600460205273ffffffffffffffffffffffffffffffffffffffff6040842092169182845260205260ff6040842054166000146121d457808352600460205260408320828452602052604083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b9295949093919573ffffffffffffffffffffffffffffffffffffffff9687600654169588811696871460001461257e578134036125205783612444915b868585469333908c611e65565b9760405196610100880188811067ffffffffffffffff821117611aaf57600797839160405216885260208801908152604088019133835260608901926000845260808a0194855260a08a0195865260c08a0196875260e08a01978c895260005260086020528160406000209a5116927fffffffffffffffffffffffff000000000000000000000000000000000000000093848c5416178b558260018c01915116848254161790558160028b0191511683825416179055600389019251169082541617905551600486015551600585015551600684015551910155565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43543a206e6174697665544f4e206e65656420616d6f756e74000000000000006044820152fd5b604051602081017f23b872dd0000000000000000000000000000000000000000000000000000000081523360248301523060448301528360648301526064825260a082019082821067ffffffffffffffff831117611aaf5760009283926040525190828b5af16125ec611c39565b81612660575b5015612602578361244491612437565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b8051801592508215612675575b5050386125f2565b6126889250602080918301019101611f68565b388061266d56fea26469706673582212205c076140fd0de0d6c40493c8274b4c0c1cbcd97474c56644d3d6b7bff43d3dfa64736f6c63430008180033
Deployed ByteCode
0x608060408181526004908136101561001657600080fd5b600092833560e01c90816301ffc9a7146117c5575080630f377395146116ce57806316019f4d1461164057806316e01724146115ed5780631785f53c146115725780632298524614611519578063248a9ca3146114d157806324d7806c146114415780632f2ff15d146113f857806336568abe1461136d57806350d2a276146112e7578063550d01a3146112805780635988ec501461101857806363a8fd8914610fd85780637048027514610f4757806375829def14610dc657806375b238fc14610d6d57806381f331da14610bc75780638800867b14610b435780638a020c6714610ad957806391d1485414610a695780639792f8d714610938578063a1e89aec146108fb578063a217fddf146108c2578063b6f7134b1461078f578063b911135f14610733578063cd4618af14610710578063d547741f146106b3578063ddf0cbf4146105e1578063e59f69c214610579578063f43b361314610522578063f5869c2f146104665763fc9dc1861461018f57600080fd5b346104625761019d3661194d565b929391946101a9611f2d565b8073ffffffffffffffffffffffffffffffffffffffff9283600554169081331491826103c9575b50506101dc9150611b0a565b858752602090600882526101f8836003868b2001541615611b6f565b86885260088252826002858a200154169583811680970361036d578789526008835261022b866007878c20015414611bd4565b878952600883528489209360038501887fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580600184870154960154169060065416811460001461033357505087808080868a5af161028d611c39565b50156102d8575091608093917f62d1466ea7dfd1b476db9e90a17828c8bb0fc5a57df551bf584a7f8a354878b495935b825194855284015246908301526060820152a26001600b5580f35b6064918451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601260248201527f63616e63656c20726566756e64206661696c00000000000000000000000000006044820152fd5b846080979593507f62d1466ea7dfd1b476db9e90a17828c8bb0fc5a57df551bf584a7f8a354878b49896949261036892611f80565b6102bd565b506064918451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f796f7572206e6f742073656c6c657200000000000000000000000000000000006044820152fd5b60209192508651938480927f6e296e450000000000000000000000000000000000000000000000000000000082525afa91821561045857906101dc92918a92610427575b508952600a6020528380868b2054169116148291386101d0565b61044a91925060203d602011610451575b6104428183611a6e565b810190611ade565b903861040d565b503d610438565b85513d8b823e3d90fd5b8280fd5b50823461051f5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261051f5782358152600860209081529082902080546001820154600283015460038401549684015460058501546006860154600790960154975173ffffffffffffffffffffffffffffffffffffffff9586168152938516968401969096529083166040830152919095166060860152608085015260a084019190915260c083015260e082015261010090f35b80fd5b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755760209073ffffffffffffffffffffffffffffffffffffffff600554169051908152f35b5080fd5b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257918192358152600a6020522073ffffffffffffffffffffffffffffffffffffffff6001818354169201541682519182526020820152f35b83827f9234c0bc9ec97c418266f9342cc42597ee66dc6f1c718161a25a8b8ba660d3e76106a8610656610613366119a6565b61062596949591939296323314611d75565b610630871515611e00565b61063b841515611e00565b610643611f2d565b60016007540180600755848885896123fa565b600754975173ffffffffffffffffffffffffffffffffffffffff9586168152919094166020820152336040820152606081019490945260808401524660a084015260c0830191909152819060e0820190565b0390a26001600b5580f35b50903461046257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104625761070c9161070760018335926106f76118aa565b948488526020528620015461209e565b612357565b5080f35b8382346105755760209061072c61072636611a0e565b91611edd565b9051908152f35b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610462578160209373ffffffffffffffffffffffffffffffffffffffff92358152600185522054169051908152f35b5090346104625761079f36611a0e565b7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec4286949392945260209280845285872033885284526107e360ff8789205416611c97565b818752600984528587209273ffffffffffffffffffffffffffffffffffffffff809116938489528552868820951694858852845260ff86882054166108665750855260098252838520908552815282842091845252812060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905580f35b606490848751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601560248201527f616c7265616479207265676973746572546f6b656e00000000000000000000006044820152fd5b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755751908152602090f35b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610575576020906007549051908152f35b5090346104625761094836611a0e565b7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42869493929452602092808452858720338852845261098c60ff8789205416611c97565b818752600984528587209273ffffffffffffffffffffffffffffffffffffffff809116938489528552868820951694858852845260ff868820541615610a0d575085526009825283852090855281528284209184525281207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905580f35b606490848751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601360248201527f616c72656164792064656c657465546f6b656e000000000000000000000000006044820152fd5b50903461046257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610462578160209360ff92610aa86118aa565b9080358352865273ffffffffffffffffffffffffffffffffffffffff83832091168252855220541690519015158152f35b838234610575576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755760209061072c610b19611882565b610b216118aa565b90610b2a6118cd565b60e4359260c4359260a435926084359260643592611e65565b5090346104625760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610462578160209360ff92610b836118aa565b610b8b6118cd565b913583526009875283832073ffffffffffffffffffffffffffffffffffffffff8092168452875283832091168252855220541690519015158152f35b508290610bd3366119a6565b9096610be494939294323314611d75565b610bef851515611e00565b610bfa881515611e00565b610c02611f2d565b818752600960205285872073ffffffffffffffffffffffffffffffffffffffff9081861689526020528688209084168852602052600160ff8789205416151503610d1057878510610c8d5750956106a8916106567f4ed7594528ea467b40aa40eeff1ebf7a53cd3771da17f533517dcd207b18b07796979860016007540180600755848885896123fa565b60849060208751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152603360248201527f54686520746f74616c416d6f756e742076616c7565206d75737420626520677260448201527f6561746572207468616e206374416d6f756e74000000000000000000000000006064820152fd5b60649060208751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601260248201527f6e6f7420726567697374657220746f6b656e00000000000000000000000000006044820152fd5b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057557602090517fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428152f35b5091903461057557602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257610e02611882565b917fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428085528282528585203386528252610e4160ff8787205416611c97565b73ffffffffffffffffffffffffffffffffffffffff84168015610eeb573314610e8f5794610e7d926001928697610e829752528520015461209e565b6120fb565b50610e8c33611d22565b80f35b606483838851917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601660248201527f41636365737369626c653a2073616d652061646d696e000000000000000000006044820152fd5b606484848951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601860248201527f41636365737369626c653a207a65726f206164647265737300000000000000006044820152fd5b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257610e7d600161070c93610f89611882565b937fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec4280885281602052828820338952602052610fca60ff848a205416611c97565b87526020528520015461209e565b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755760ff602092541690519015158152f35b5091903461057557611029366118f0565b969391949290507fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428652602092808452848720338852845261107060ff8689205416611c97565b611078611f2d565b8587526008845273ffffffffffffffffffffffffffffffffffffffff926110a7846003888b2001541615611b6f565b868852600885526110bf896007888b20015414611bd4565b821561126b575b8688526008855285882094600386019285831693847fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790558086600189015416970154938660065416881460001461122b578a80808781945af161112c611c39565b50156111d05750917ff8cde1fe2cd0b62a858b3e46ed74ad19f4de0483236632b75745d688c727af20979899939160086106a896945b8b8d5252878b20936002818654169501541697519788974695899491909360e096939998979461010087019a73ffffffffffffffffffffffffffffffffffffffff8094818094168a52166020890152166040870152166060850152608084015260a083015260c08201520152565b6064918851917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600a60248201527f636c61696d206661696c000000000000000000000000000000000000000000006044820152fd5b5050918160086106a89694611266847ff8cde1fe2cd0b62a858b3e46ed74ad19f4de0483236632b75745d688c727af209c9d9e98968b611f80565b611162565b868852600885528588206005015492506110c6565b8382346105755760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755760ff8160209373ffffffffffffffffffffffffffffffffffffffff6112d4611882565b1681526002855220541690519015158152f35b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257357fffffffff00000000000000000000000000000000000000000000000000000000811680910361046257818373ffffffffffffffffffffffffffffffffffffffff9260209552600385522054169051908152f35b5082903461057557807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610575576113a66118aa565b903373ffffffffffffffffffffffffffffffffffffffff8316036113d0575061070c919235612357565b8390517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b50903461046257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104625761070c9161143c60018335926106f76118aa565b6121d9565b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610462578160209360ff92611481611882565b907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428352865273ffffffffffffffffffffffffffffffffffffffff83832091168252855220541690519015158152f35b5090346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257816020938260019335825285522001549051908152f35b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057557602090517ffb5864e8ff833c3cb2d2d08505e82ff02a43554c74a35d4f5a64e852612783118152f35b833461051f5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261051f57610e8c6115ad611882565b3360009081527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b6902260205260409020546115e89060ff16611c97565b611d22565b83823461057557817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105755760209073ffffffffffffffffffffffffffffffffffffffff600654169051908152f35b50346104625761164f3661194d565b3360009081527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b69022602052604090205492959394909390929091506116959060ff16611c97565b61169d611f2d565b84865260206008815273ffffffffffffffffffffffffffffffffffffffff916101f8836003868b2001541615611b6f565b50919034610575576116df366118f0565b9693929091946116ed611f2d565b8073ffffffffffffffffffffffffffffffffffffffff93846005541690813314918261173c575b50506117209150611b0a565b858752602093600885526110a7846003888b2001541615611b6f565b60209192508851938480927f6e296e450000000000000000000000000000000000000000000000000000000082525afa9182156117bb579061172092918a9261179a575b508952600a6020528480888b205416911614829138611714565b6117b491925060203d602011610451576104428183611a6e565b9038611780565b87513d8b823e3d90fd5b849084346104625760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046257357fffffffff00000000000000000000000000000000000000000000000000000000811680910361046257602092507f7965db0b000000000000000000000000000000000000000000000000000000008114908115611858575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483611851565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036118a557565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff821682036118a557565b6044359073ffffffffffffffffffffffffffffffffffffffff821682036118a557565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a09101126118a55760043573ffffffffffffffffffffffffffffffffffffffff811681036118a5579060243590604435906064359060843590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60809101126118a55760043573ffffffffffffffffffffffffffffffffffffffff811681036118a55790602435906044359060643590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a09101126118a55773ffffffffffffffffffffffffffffffffffffffff9060043582811681036118a5579160243590811681036118a55790604435906064359060843590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126118a55773ffffffffffffffffffffffffffffffffffffffff9060043582811681036118a5579160243590811681036118a5579060443590565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611aaf57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b908160209103126118a5575173ffffffffffffffffffffffffffffffffffffffff811681036118a55790565b15611b1157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6f6e6c792063616c6c206c3146617374576974686472617700000000000000006044820152fd5b15611b7657565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f616c726561647920736f6c6400000000000000000000000000000000000000006044820152fd5b15611bdb57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f486173682076616c75657320646f206e6f74206d6174636800000000000000006044820152fd5b3d15611c92573d9067ffffffffffffffff8211611aaf5760405191611c8660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611a6e565b82523d6000602084013e565b606090565b15611c9e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f41636365737369626c653a2043616c6c6572206973206e6f7420616e2061646d60448201527f696e0000000000000000000000000000000000000000000000000000000000006064820152fd5b3373ffffffffffffffffffffffffffffffffffffffff821603611d4b57611d4890612280565b50565b60046040517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b15611d7c57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f4c3246573a2066756e6374696f6e2063616e206f6e6c792062652063616c6c6560448201527f642066726f6d20616e20454f41000000000000000000000000000000000000006064820152fd5b15611e0757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e70757420616d6f756e74206e656564206e6f6e5a65726f000000000000006044820152fd5b969492909593919560405196602088019873ffffffffffffffffffffffffffffffffffffffff92838092168b52166040890152166060870152608086015260a085015260c084015260e083015261010090818301528152610120810181811067ffffffffffffffff821117611aaf5760405251902090565b600554919273ffffffffffffffffffffffffffffffffffffffff929091831690831614611f0c57505050600190565b600052600a6020528060406000205416911603611f2857600390565b600290565b6002600b5414611f3e576002600b55565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b908160209103126118a5575180151581036118a55790565b91909173ffffffffffffffffffffffffffffffffffffffff92604051928460208501927fa9059cbb0000000000000000000000000000000000000000000000000000000084521660248501526044840152604483526080830183811067ffffffffffffffff821117611aaf57600094859485926040525193165af1612003611c39565b8161206f575b501561201157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b8051801592508215612084575b505038612009565b6120979250602080918301019101611f68565b388061207c565b80600052600460205260406000203360005260205260ff60406000205416156120c45750565b604490604051907fe2517d3f0000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b73ffffffffffffffffffffffffffffffffffffffff1660008181527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b6902260205260408120549091907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec429060ff166121d4578083526004602052604083208284526020526040832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b505090565b90600091808352600460205273ffffffffffffffffffffffffffffffffffffffff6040842092169182845260205260ff604084205416156000146121d4578083526004602052604083208284526020526040832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b73ffffffffffffffffffffffffffffffffffffffff1660008181527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b6902260205260408120549091907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec429060ff16156121d457808352600460205260408320828452602052604083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b90600091808352600460205273ffffffffffffffffffffffffffffffffffffffff6040842092169182845260205260ff6040842054166000146121d457808352600460205260408320828452602052604083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b9295949093919573ffffffffffffffffffffffffffffffffffffffff9687600654169588811696871460001461257e578134036125205783612444915b868585469333908c611e65565b9760405196610100880188811067ffffffffffffffff821117611aaf57600797839160405216885260208801908152604088019133835260608901926000845260808a0194855260a08a0195865260c08a0196875260e08a01978c895260005260086020528160406000209a5116927fffffffffffffffffffffffff000000000000000000000000000000000000000093848c5416178b558260018c01915116848254161790558160028b0191511683825416179055600389019251169082541617905551600486015551600585015551600684015551910155565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43543a206e6174697665544f4e206e65656420616d6f756e74000000000000006044820152fd5b604051602081017f23b872dd0000000000000000000000000000000000000000000000000000000081523360248301523060448301528360648301526064825260a082019082821067ffffffffffffffff831117611aaf5760009283926040525190828b5af16125ec611c39565b81612660575b5015612602578361244491612437565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b8051801592508215612675575b5050386125f2565b6126889250602080918301019101611f68565b388061266d56fea26469706673582212205c076140fd0de0d6c40493c8274b4c0c1cbcd97474c56644d3d6b7bff43d3dfa64736f6c63430008180033