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-10-01T15:58:36.865700Z
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 /// %% WARNING %% /// We do not support ERC20, which is specially created and incurs a fee when transferring. /// And In the current version, we plan to register RegisteredToken based on the same token as the current one, /// so it is logical that totalAmount >= ctAmount is greater. /// @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 /// %% WARNING %% /// We do not support ERC20, which is specially created and incurs a fee when transferring. /// @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 { require(chainData[_l1chainId].l1CrossTradeContract != address(0), "This chain is not supported."); 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 ); } /// @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/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; } } }
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); }
@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; } }
@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); }
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/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":"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":"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":"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
0x6080806040523461001b576001600b5561253c90816100218239f35b600080fdfe6080604081815260048036101561001557600080fd5b600092833560e01c90816301ffc9a714611742575080630f3773951461144657806316e01724146113f35780631785f53c14611374578063229852461461131b578063248a9ca3146112d457806324d7806c146112455780632f2ff15d146111fd57806336568abe1461117257806350d2a276146110ed578063550d01a31461108657806363a8fd89146110465780637048027514610fb657806375829def14610e3557806375b238fc14610ddc57806381f331da14610c365780638800867b14610bb35780638a020c6714610b4257806391d1485414610ad35780639792f8d7146109a3578063a1e89aec14610966578063a217fddf1461092d578063b6f7134b146107fb578063b911135f146107a0578063d547741f14610744578063ddf0cbf4146105e8578063e59f69c214610581578063f43b36131461052a578063f5869c2f1461046e5763fc9dc1861461016d57600080fd5b3461046a5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a576101a46117ff565b9060243592606435916101b5611da4565b73ffffffffffffffffffffffffffffffffffffffff9080826005541680331490816103d3575b506101e691506119d1565b85875260209060088252610202836003868b2001541615611a36565b86885260088252826002858a20015416958381168097036103775787895260088352610235866007878c20015414611a9b565b878952600883528489209360038501887fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580600184870154960154169060065416811460001461033d57505087808080868a5af1610297611b00565b50156102e2575091608093917f62d1466ea7dfd1b476db9e90a17828c8bb0fc5a57df551bf584a7f8a354878b495935b825194855284015246908301526060820152a26001600b5580f35b6064918451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601260248201527f63616e63656c20726566756e64206661696c00000000000000000000000000006044820152fd5b846080979593507f62d1466ea7dfd1b476db9e90a17828c8bb0fc5a57df551bf584a7f8a354878b49896949261037292611df7565b6102c7565b506064918451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f796f7572206e6f742073656c6c657200000000000000000000000000000000006044820152fd5b602091508551928380927f6e296e450000000000000000000000000000000000000000000000000000000082525afa90811561046057906101e6918991610431575b506044358952600a6020528380868b20541691161482916101db565b610453915060203d602011610459575b61044b8183611935565b8101906119a5565b38610415565b503d610441565b84513d8a823e3d90fd5b8280fd5b5091346105275760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105275782358152600860209081529082902080546001820154600283015460038401549684015460058501546006860154600790960154975173ffffffffffffffffffffffffffffffffffffffff9586168152938516968401969096529083166040830152919095166060860152608085015260a084019190915260c083015260e082015261010090f35b80fd5b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d5760209073ffffffffffffffffffffffffffffffffffffffff600554169051908152f35b5080fd5b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57918192358152600a6020522073ffffffffffffffffffffffffffffffffffffffff6001818354169201541682519182526020820152f35b5091906105f43661186d565b909661060594939294323314611c3c565b610610851515611cc7565b61061b881515611cc7565b610623611da4565b818752600a60205273ffffffffffffffffffffffffffffffffffffffff8688205416156106e75750956106dc9161068a7f9234c0bc9ec97c418266f9342cc42597ee66dc6f1c718161a25a8b8ba660d3e79697986001600754018060075584888589612271565b600754975173ffffffffffffffffffffffffffffffffffffffff9586168152919094166020820152336040820152606081019490945260808401524660a084015260c0830191909152819060e0820190565b0390a26001600b5580f35b60649060208751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601c60248201527f5468697320636861696e206973206e6f7420737570706f727465642e000000006044820152fd5b503461046a57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a5761079c916107976001833592610787611827565b9484885260205286200154611f15565b6121ce565b5080f35b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a578160209373ffffffffffffffffffffffffffffffffffffffff92358152600185522054169051908152f35b503461046a5761080a366118d5565b7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42869493929452602092808452858720338852845261084e60ff8789205416611b5e565b818752600984528587209273ffffffffffffffffffffffffffffffffffffffff809116938489528552868820951694858852845260ff86882054166108d15750855260098252838520908552815282842091845252812060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905580f35b606490848751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601560248201527f616c7265616479207265676973746572546f6b656e00000000000000000000006044820152fd5b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d5751908152602090f35b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d576020906007549051908152f35b503461046a576109b2366118d5565b7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec4286949392945260209280845285872033885284526109f660ff8789205416611b5e565b818752600984528587209273ffffffffffffffffffffffffffffffffffffffff809116938489528552868820951694858852845260ff868820541615610a77575085526009825283852090855281528284209184525281207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905580f35b606490848751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601360248201527f616c72656164792064656c657465546f6b656e000000000000000000000000006044820152fd5b503461046a57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a578160209360ff92610b11611827565b9080358352865273ffffffffffffffffffffffffffffffffffffffff83832091168252855220541690519015158152f35b50503461057d576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d57602090610bac610b826117ff565b610b8a611827565b90610b9361184a565b60e4359260c4359260a435926084359260643592611d2c565b9051908152f35b503461046a5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a578160209360ff92610bf2611827565b610bfa61184a565b913583526009875283832073ffffffffffffffffffffffffffffffffffffffff8092168452875283832091168252855220541690519015158152f35b509190610c423661186d565b9096610c5394939294323314611c3c565b610c5e851515611cc7565b610c69881515611cc7565b610c71611da4565b818752600960205285872073ffffffffffffffffffffffffffffffffffffffff9081861689526020528688209084168852602052600160ff8789205416151503610d7f57878510610cfc5750956106dc9161068a7f4ed7594528ea467b40aa40eeff1ebf7a53cd3771da17f533517dcd207b18b0779697986001600754018060075584888589612271565b60849060208751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152603360248201527f54686520746f74616c416d6f756e742076616c7565206d75737420626520677260448201527f6561746572207468616e206374416d6f756e74000000000000000000000000006064820152fd5b60649060208751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601260248201527f6e6f7420726567697374657220746f6b656e00000000000000000000000000006044820152fd5b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d57602090517fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428152f35b5082903461057d57602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57610e716117ff565b917fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428085528282528585203386528252610eb060ff8787205416611b5e565b73ffffffffffffffffffffffffffffffffffffffff84168015610f5a573314610efe5794610eec926001928697610ef197525285200154611f15565b611f72565b50610efb33611be9565b80f35b606483838851917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601660248201527f41636365737369626c653a2073616d652061646d696e000000000000000000006044820152fd5b606484848951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601860248201527f41636365737369626c653a207a65726f206164647265737300000000000000006044820152fd5b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57610eec600161079c93610ff76117ff565b937fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428088528160205282882033895260205261103860ff848a205416611b5e565b875260205285200154611f15565b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d5760ff602092541690519015158152f35b50503461057d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d5760ff8160209373ffffffffffffffffffffffffffffffffffffffff6110da6117ff565b1681526002855220541690519015158152f35b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57357fffffffff00000000000000000000000000000000000000000000000000000000811680910361046a57818373ffffffffffffffffffffffffffffffffffffffff9260209552600385522054169051908152f35b5091903461057d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d576111ab611827565b903373ffffffffffffffffffffffffffffffffffffffff8316036111d5575061079c9192356121ce565b8390517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b503461046a57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a5761079c916112406001833592610787611827565b612050565b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a578160209360ff926112846117ff565b907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428352865273ffffffffffffffffffffffffffffffffffffffff83832091168252855220541690519015158152f35b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57816020938260019335825285522001549051908152f35b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d57602090517ffb5864e8ff833c3cb2d2d08505e82ff02a43554c74a35d4f5a64e852612783118152f35b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a576113ee60ff610efb936113b56117ff565b937fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42875260205280862033875260205285205416611b5e565b611be9565b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d5760209073ffffffffffffffffffffffffffffffffffffffff600654169051908152f35b5082903461057d5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d576114806117ff565b92602435936044359260843595611495611da4565b73ffffffffffffffffffffffffffffffffffffffff9180836005541680331490816116bb575b506114c691506119d1565b858752602093600885526114e2846003888b2001541615611a36565b868852600885526114fa896007888b20015414611a9b565b82156116a6575b8688526008855285882094600386019285831693847fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580866001890154169701549386600654168814600014611666578a80808781945af1611567611b00565b501561160b5750917ff8cde1fe2cd0b62a858b3e46ed74ad19f4de0483236632b75745d688c727af20979899939160086106dc96945b8b8d5252878b20936002818654169501541697519788974695899491909360e096939998979461010087019a73ffffffffffffffffffffffffffffffffffffffff8094818094168a52166020890152166040870152166060850152608084015260a083015260c08201520152565b6064918851917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600a60248201527f636c61696d206661696c000000000000000000000000000000000000000000006044820152fd5b5050918160086106dc96946116a1847ff8cde1fe2cd0b62a858b3e46ed74ad19f4de0483236632b75745d688c727af209c9d9e98968b611df7565b61159d565b86885260088552858820600501549250611501565b602091508751928380927f6e296e450000000000000000000000000000000000000000000000000000000082525afa90811561173857906114c6918991611719575b506064358952600a6020528480888b20541691161482916114bb565b611732915060203d6020116104595761044b8183611935565b8a6116fd565b86513d8a823e3d90fd5b9250503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57357fffffffff00000000000000000000000000000000000000000000000000000000811680910361046a57602092507f7965db0b0000000000000000000000000000000000000000000000000000000081149081156117d5575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014386117ce565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361182257565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361182257565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361182257565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a09101126118225773ffffffffffffffffffffffffffffffffffffffff906004358281168103611822579160243590811681036118225790604435906064359060843590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126118225773ffffffffffffffffffffffffffffffffffffffff90600435828116810361182257916024359081168103611822579060443590565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761197657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90816020910312611822575173ffffffffffffffffffffffffffffffffffffffff811681036118225790565b156119d857565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6f6e6c792063616c6c206c3146617374576974686472617700000000000000006044820152fd5b15611a3d57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f616c726561647920736f6c6400000000000000000000000000000000000000006044820152fd5b15611aa257565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f486173682076616c75657320646f206e6f74206d6174636800000000000000006044820152fd5b3d15611b59573d9067ffffffffffffffff82116119765760405191611b4d60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611935565b82523d6000602084013e565b606090565b15611b6557565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f41636365737369626c653a2043616c6c6572206973206e6f7420616e2061646d60448201527f696e0000000000000000000000000000000000000000000000000000000000006064820152fd5b3373ffffffffffffffffffffffffffffffffffffffff821603611c1257611c0f906120f7565b50565b60046040517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b15611c4357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f4c3246573a2066756e6374696f6e2063616e206f6e6c792062652063616c6c6560448201527f642066726f6d20616e20454f41000000000000000000000000000000000000006064820152fd5b15611cce57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e70757420616d6f756e74206e656564206e6f6e5a65726f000000000000006044820152fd5b969492909593919560405196602088019873ffffffffffffffffffffffffffffffffffffffff92838092168b52166040890152166060870152608086015260a085015260c084015260e083015261010090818301528152610120810181811067ffffffffffffffff8211176119765760405251902090565b6002600b5414611db5576002600b55565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b90816020910312611822575180151581036118225790565b91909173ffffffffffffffffffffffffffffffffffffffff92604051928460208501927fa9059cbb0000000000000000000000000000000000000000000000000000000084521660248501526044840152604483526080830183811067ffffffffffffffff82111761197657600094859485926040525193165af1611e7a611b00565b81611ee6575b5015611e8857565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b8051801592508215611efb575b505038611e80565b611f0e9250602080918301019101611ddf565b3880611ef3565b80600052600460205260406000203360005260205260ff6040600020541615611f3b5750565b604490604051907fe2517d3f0000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b73ffffffffffffffffffffffffffffffffffffffff1660008181527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b6902260205260408120549091907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec429060ff1661204b578083526004602052604083208284526020526040832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b505090565b90600091808352600460205273ffffffffffffffffffffffffffffffffffffffff6040842092169182845260205260ff6040842054161560001461204b578083526004602052604083208284526020526040832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b73ffffffffffffffffffffffffffffffffffffffff1660008181527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b6902260205260408120549091907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec429060ff161561204b57808352600460205260408320828452602052604083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b90600091808352600460205273ffffffffffffffffffffffffffffffffffffffff6040842092169182845260205260ff60408420541660001461204b57808352600460205260408320828452602052604083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b9295949093919573ffffffffffffffffffffffffffffffffffffffff968760065416958881169687146000146123f55781340361239757836122bb915b868585469333908c611d2c565b9760405196610100880188811067ffffffffffffffff82111761197657600797839160405216885260208801908152604088019133835260608901926000845260808a0194855260a08a0195865260c08a0196875260e08a01978c895260005260086020528160406000209a5116927fffffffffffffffffffffffff000000000000000000000000000000000000000093848c5416178b558260018c01915116848254161790558160028b0191511683825416179055600389019251169082541617905551600486015551600585015551600684015551910155565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43543a206e6174697665544f4e206e65656420616d6f756e74000000000000006044820152fd5b604051602081017f23b872dd0000000000000000000000000000000000000000000000000000000081523360248301523060448301528360648301526064825260a082019082821067ffffffffffffffff8311176119765760009283926040525190828b5af1612463611b00565b816124d7575b501561247957836122bb916122ae565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b80518015925082156124ec575b505038612469565b6124ff9250602080918301019101611ddf565b38806124e456fea264697066735822122093ca998800626e2f531ee16d15a018d55ef8d490b91935d9e91dbda198992ef964736f6c63430008180033
Deployed ByteCode
0x6080604081815260048036101561001557600080fd5b600092833560e01c90816301ffc9a714611742575080630f3773951461144657806316e01724146113f35780631785f53c14611374578063229852461461131b578063248a9ca3146112d457806324d7806c146112455780632f2ff15d146111fd57806336568abe1461117257806350d2a276146110ed578063550d01a31461108657806363a8fd89146110465780637048027514610fb657806375829def14610e3557806375b238fc14610ddc57806381f331da14610c365780638800867b14610bb35780638a020c6714610b4257806391d1485414610ad35780639792f8d7146109a3578063a1e89aec14610966578063a217fddf1461092d578063b6f7134b146107fb578063b911135f146107a0578063d547741f14610744578063ddf0cbf4146105e8578063e59f69c214610581578063f43b36131461052a578063f5869c2f1461046e5763fc9dc1861461016d57600080fd5b3461046a5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a576101a46117ff565b9060243592606435916101b5611da4565b73ffffffffffffffffffffffffffffffffffffffff9080826005541680331490816103d3575b506101e691506119d1565b85875260209060088252610202836003868b2001541615611a36565b86885260088252826002858a20015416958381168097036103775787895260088352610235866007878c20015414611a9b565b878952600883528489209360038501887fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580600184870154960154169060065416811460001461033d57505087808080868a5af1610297611b00565b50156102e2575091608093917f62d1466ea7dfd1b476db9e90a17828c8bb0fc5a57df551bf584a7f8a354878b495935b825194855284015246908301526060820152a26001600b5580f35b6064918451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601260248201527f63616e63656c20726566756e64206661696c00000000000000000000000000006044820152fd5b846080979593507f62d1466ea7dfd1b476db9e90a17828c8bb0fc5a57df551bf584a7f8a354878b49896949261037292611df7565b6102c7565b506064918451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f796f7572206e6f742073656c6c657200000000000000000000000000000000006044820152fd5b602091508551928380927f6e296e450000000000000000000000000000000000000000000000000000000082525afa90811561046057906101e6918991610431575b506044358952600a6020528380868b20541691161482916101db565b610453915060203d602011610459575b61044b8183611935565b8101906119a5565b38610415565b503d610441565b84513d8a823e3d90fd5b8280fd5b5091346105275760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105275782358152600860209081529082902080546001820154600283015460038401549684015460058501546006860154600790960154975173ffffffffffffffffffffffffffffffffffffffff9586168152938516968401969096529083166040830152919095166060860152608085015260a084019190915260c083015260e082015261010090f35b80fd5b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d5760209073ffffffffffffffffffffffffffffffffffffffff600554169051908152f35b5080fd5b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57918192358152600a6020522073ffffffffffffffffffffffffffffffffffffffff6001818354169201541682519182526020820152f35b5091906105f43661186d565b909661060594939294323314611c3c565b610610851515611cc7565b61061b881515611cc7565b610623611da4565b818752600a60205273ffffffffffffffffffffffffffffffffffffffff8688205416156106e75750956106dc9161068a7f9234c0bc9ec97c418266f9342cc42597ee66dc6f1c718161a25a8b8ba660d3e79697986001600754018060075584888589612271565b600754975173ffffffffffffffffffffffffffffffffffffffff9586168152919094166020820152336040820152606081019490945260808401524660a084015260c0830191909152819060e0820190565b0390a26001600b5580f35b60649060208751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601c60248201527f5468697320636861696e206973206e6f7420737570706f727465642e000000006044820152fd5b503461046a57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a5761079c916107976001833592610787611827565b9484885260205286200154611f15565b6121ce565b5080f35b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a578160209373ffffffffffffffffffffffffffffffffffffffff92358152600185522054169051908152f35b503461046a5761080a366118d5565b7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42869493929452602092808452858720338852845261084e60ff8789205416611b5e565b818752600984528587209273ffffffffffffffffffffffffffffffffffffffff809116938489528552868820951694858852845260ff86882054166108d15750855260098252838520908552815282842091845252812060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905580f35b606490848751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601560248201527f616c7265616479207265676973746572546f6b656e00000000000000000000006044820152fd5b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d5751908152602090f35b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d576020906007549051908152f35b503461046a576109b2366118d5565b7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec4286949392945260209280845285872033885284526109f660ff8789205416611b5e565b818752600984528587209273ffffffffffffffffffffffffffffffffffffffff809116938489528552868820951694858852845260ff868820541615610a77575085526009825283852090855281528284209184525281207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905580f35b606490848751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601360248201527f616c72656164792064656c657465546f6b656e000000000000000000000000006044820152fd5b503461046a57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a578160209360ff92610b11611827565b9080358352865273ffffffffffffffffffffffffffffffffffffffff83832091168252855220541690519015158152f35b50503461057d576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d57602090610bac610b826117ff565b610b8a611827565b90610b9361184a565b60e4359260c4359260a435926084359260643592611d2c565b9051908152f35b503461046a5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a578160209360ff92610bf2611827565b610bfa61184a565b913583526009875283832073ffffffffffffffffffffffffffffffffffffffff8092168452875283832091168252855220541690519015158152f35b509190610c423661186d565b9096610c5394939294323314611c3c565b610c5e851515611cc7565b610c69881515611cc7565b610c71611da4565b818752600960205285872073ffffffffffffffffffffffffffffffffffffffff9081861689526020528688209084168852602052600160ff8789205416151503610d7f57878510610cfc5750956106dc9161068a7f4ed7594528ea467b40aa40eeff1ebf7a53cd3771da17f533517dcd207b18b0779697986001600754018060075584888589612271565b60849060208751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152603360248201527f54686520746f74616c416d6f756e742076616c7565206d75737420626520677260448201527f6561746572207468616e206374416d6f756e74000000000000000000000000006064820152fd5b60649060208751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601260248201527f6e6f7420726567697374657220746f6b656e00000000000000000000000000006044820152fd5b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d57602090517fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428152f35b5082903461057d57602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57610e716117ff565b917fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428085528282528585203386528252610eb060ff8787205416611b5e565b73ffffffffffffffffffffffffffffffffffffffff84168015610f5a573314610efe5794610eec926001928697610ef197525285200154611f15565b611f72565b50610efb33611be9565b80f35b606483838851917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601660248201527f41636365737369626c653a2073616d652061646d696e000000000000000000006044820152fd5b606484848951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601860248201527f41636365737369626c653a207a65726f206164647265737300000000000000006044820152fd5b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57610eec600161079c93610ff76117ff565b937fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428088528160205282882033895260205261103860ff848a205416611b5e565b875260205285200154611f15565b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d5760ff602092541690519015158152f35b50503461057d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d5760ff8160209373ffffffffffffffffffffffffffffffffffffffff6110da6117ff565b1681526002855220541690519015158152f35b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57357fffffffff00000000000000000000000000000000000000000000000000000000811680910361046a57818373ffffffffffffffffffffffffffffffffffffffff9260209552600385522054169051908152f35b5091903461057d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d576111ab611827565b903373ffffffffffffffffffffffffffffffffffffffff8316036111d5575061079c9192356121ce565b8390517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b503461046a57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a5761079c916112406001833592610787611827565b612050565b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a578160209360ff926112846117ff565b907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec428352865273ffffffffffffffffffffffffffffffffffffffff83832091168252855220541690519015158152f35b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57816020938260019335825285522001549051908152f35b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d57602090517ffb5864e8ff833c3cb2d2d08505e82ff02a43554c74a35d4f5a64e852612783118152f35b503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a576113ee60ff610efb936113b56117ff565b937fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42875260205280862033875260205285205416611b5e565b611be9565b50503461057d57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d5760209073ffffffffffffffffffffffffffffffffffffffff600654169051908152f35b5082903461057d5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261057d576114806117ff565b92602435936044359260843595611495611da4565b73ffffffffffffffffffffffffffffffffffffffff9180836005541680331490816116bb575b506114c691506119d1565b858752602093600885526114e2846003888b2001541615611a36565b868852600885526114fa896007888b20015414611a9b565b82156116a6575b8688526008855285882094600386019285831693847fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580866001890154169701549386600654168814600014611666578a80808781945af1611567611b00565b501561160b5750917ff8cde1fe2cd0b62a858b3e46ed74ad19f4de0483236632b75745d688c727af20979899939160086106dc96945b8b8d5252878b20936002818654169501541697519788974695899491909360e096939998979461010087019a73ffffffffffffffffffffffffffffffffffffffff8094818094168a52166020890152166040870152166060850152608084015260a083015260c08201520152565b6064918851917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600a60248201527f636c61696d206661696c000000000000000000000000000000000000000000006044820152fd5b5050918160086106dc96946116a1847ff8cde1fe2cd0b62a858b3e46ed74ad19f4de0483236632b75745d688c727af209c9d9e98968b611df7565b61159d565b86885260088552858820600501549250611501565b602091508751928380927f6e296e450000000000000000000000000000000000000000000000000000000082525afa90811561173857906114c6918991611719575b506064358952600a6020528480888b20541691161482916114bb565b611732915060203d6020116104595761044b8183611935565b8a6116fd565b86513d8a823e3d90fd5b9250503461046a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046a57357fffffffff00000000000000000000000000000000000000000000000000000000811680910361046a57602092507f7965db0b0000000000000000000000000000000000000000000000000000000081149081156117d5575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014386117ce565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361182257565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361182257565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361182257565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a09101126118225773ffffffffffffffffffffffffffffffffffffffff906004358281168103611822579160243590811681036118225790604435906064359060843590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126118225773ffffffffffffffffffffffffffffffffffffffff90600435828116810361182257916024359081168103611822579060443590565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761197657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90816020910312611822575173ffffffffffffffffffffffffffffffffffffffff811681036118225790565b156119d857565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6f6e6c792063616c6c206c3146617374576974686472617700000000000000006044820152fd5b15611a3d57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f616c726561647920736f6c6400000000000000000000000000000000000000006044820152fd5b15611aa257565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f486173682076616c75657320646f206e6f74206d6174636800000000000000006044820152fd5b3d15611b59573d9067ffffffffffffffff82116119765760405191611b4d60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611935565b82523d6000602084013e565b606090565b15611b6557565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f41636365737369626c653a2043616c6c6572206973206e6f7420616e2061646d60448201527f696e0000000000000000000000000000000000000000000000000000000000006064820152fd5b3373ffffffffffffffffffffffffffffffffffffffff821603611c1257611c0f906120f7565b50565b60046040517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b15611c4357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f4c3246573a2066756e6374696f6e2063616e206f6e6c792062652063616c6c6560448201527f642066726f6d20616e20454f41000000000000000000000000000000000000006064820152fd5b15611cce57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e70757420616d6f756e74206e656564206e6f6e5a65726f000000000000006044820152fd5b969492909593919560405196602088019873ffffffffffffffffffffffffffffffffffffffff92838092168b52166040890152166060870152608086015260a085015260c084015260e083015261010090818301528152610120810181811067ffffffffffffffff8211176119765760405251902090565b6002600b5414611db5576002600b55565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b90816020910312611822575180151581036118225790565b91909173ffffffffffffffffffffffffffffffffffffffff92604051928460208501927fa9059cbb0000000000000000000000000000000000000000000000000000000084521660248501526044840152604483526080830183811067ffffffffffffffff82111761197657600094859485926040525193165af1611e7a611b00565b81611ee6575b5015611e8857565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b8051801592508215611efb575b505038611e80565b611f0e9250602080918301019101611ddf565b3880611ef3565b80600052600460205260406000203360005260205260ff6040600020541615611f3b5750565b604490604051907fe2517d3f0000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b73ffffffffffffffffffffffffffffffffffffffff1660008181527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b6902260205260408120549091907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec429060ff1661204b578083526004602052604083208284526020526040832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b505090565b90600091808352600460205273ffffffffffffffffffffffffffffffffffffffff6040842092169182845260205260ff6040842054161560001461204b578083526004602052604083208284526020526040832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b73ffffffffffffffffffffffffffffffffffffffff1660008181527f2fb794d17134dfdec181ddbac1babb5ab1eb140204ef4d982f294e7fc8b6902260205260408120549091907fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec429060ff161561204b57808352600460205260408320828452602052604083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b90600091808352600460205273ffffffffffffffffffffffffffffffffffffffff6040842092169182845260205260ff60408420541660001461204b57808352600460205260408320828452602052604083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b9295949093919573ffffffffffffffffffffffffffffffffffffffff968760065416958881169687146000146123f55781340361239757836122bb915b868585469333908c611d2c565b9760405196610100880188811067ffffffffffffffff82111761197657600797839160405216885260208801908152604088019133835260608901926000845260808a0194855260a08a0195865260c08a0196875260e08a01978c895260005260086020528160406000209a5116927fffffffffffffffffffffffff000000000000000000000000000000000000000093848c5416178b558260018c01915116848254161790558160028b0191511683825416179055600389019251169082541617905551600486015551600585015551600684015551910155565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43543a206e6174697665544f4e206e65656420616d6f756e74000000000000006044820152fd5b604051602081017f23b872dd0000000000000000000000000000000000000000000000000000000081523360248301523060448301528360648301526064825260a082019082821067ffffffffffffffff8311176119765760009283926040525190828b5af1612463611b00565b816124d7575b501561247957836122bb916122ae565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b80518015925082156124ec575b505038612469565b6124ff9250602080918301019101611ddf565b38806124e456fea264697066735822122093ca998800626e2f531ee16d15a018d55ef8d490b91935d9e91dbda198992ef964736f6c63430008180033