Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- HashedTimeLockERC20
- Optimization enabled
- true
- Compiler version
- v0.8.23+commit.f704f362
- Optimization runs
- 200
- EVM Version
- paris
- Verified at
- 2024-08-06T11:24:27.512190Z
contracts/HashedTimeLockERC20.sol
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; /** * @title Hashed Timelock locks (HTLCs) on Ethereum ERC20 tokens. * * This contract provides a way to lock and keep HTLCs for ERC20 tokens. * * Protocol: * * 1) lock(srcReceiver, hashlock, timelock, tokenContract, amount) - a * sender calls this to lock a new HTLC on a given token (tokenContract) * for a given amount. A 32 byte contract id is returned * 2) redeem(contractId, secret) - once the srcReceiver knows the secret of * the hashlock hash they can claim the tokens with this function * 3) unlock() - after timelock has expired and if the srcReceiver did not * redeem the tokens the sender / creator of the HTLC can get their tokens * back with this function. */ interface IMessenger { function notify( bytes32 commitId, bytes32 hashlock, string memory dstChain, string memory dstAsset, string memory dstAddress, string memory srcAsset, address payable sender, address payable srcReceiver, uint256 amount, uint256 timelock, address tokenContract ) external; } contract HashedTimeLockERC20 { error FundsNotSent(); error NotFutureTimelock(); error NotPassedTimelock(); error LockAlreadyExists(); error CommitIdAlreadyExists(); error LockNotExists(); error HashlockNotMatch(); error AlreadyRedeemed(); error AlreadyUnlocked(); error NoMessenger(); error CommitmentNotExists(); error IncorrectData(); error InsufficientBalance(); error NoAllowance(); error AlreadyLocked(); error AlreadyUncommitted(); struct HTLC { string dstAddress; string dstChain; string dstAsset; string srcAsset; address payable sender; address payable srcReceiver; bytes32 hashlock; uint256 secret; uint256 amount; uint256 timelock; address tokenContract; bool redeemed; bool unlocked; } struct PHTLC { string dstAddress; string dstChain; string dstAsset; string srcAsset; address payable sender; address payable srcReceiver; uint timelock; uint amount; address messenger; address tokenContract; bool locked; bool uncommitted; } using SafeERC20 for IERC20; mapping(bytes32 => HTLC) locks; mapping(bytes32 => PHTLC) commits; mapping(bytes32 => bytes32) commitIdToLockId; bytes32[] lockIds; bytes32[] commitIds; bytes32 blockHash = blockhash(block.number - 1); uint256 blockHashAsUint = uint256(blockHash); uint256 contractNonce = 0; event TokenLocked( bytes32 indexed hashlock, string dstChain, string dstAddress, string dstAsset, address indexed sender, address indexed srcReceiver, string srcAsset, uint amount, uint timelock, address messenger, bytes32 commitId, address tokenContract ); event TokenRedeemed(bytes32 indexed lockId, address redeemAddress); event TokenUnlocked(bytes32 indexed lockId); event TokenCommitted( bytes32 commitId, string[] hopChains, string[] hopAssets, string[] hopAddresses, string dstChain, string dstAddress, string dstAsset, address sender, address srcReceiver, string srcAsset, uint amount, uint timelock, address messenger, address tokenContract ); event LowLevelErrorOccurred(bytes lowLevelData); event TokenUncommitted(bytes32 indexed commitId); modifier _committed(bytes32 commitId) { if (!hasPHTLC(commitId)) revert CommitmentNotExists(); _; } modifier _locked(bytes32 lockId) { if (!hasHTLC(lockId)) revert LockNotExists(); _; } function commit( string[] memory hopChains, string[] memory hopAssets, string[] memory hopAddresses, string memory dstChain, string memory dstAsset, string memory dstAddress, string memory srcAsset, address srcReceiver, uint timelock, address messenger, uint amount, address tokenContract ) external payable returns (bytes32 commitId) { if (amount == 0) { revert FundsNotSent(); } if (timelock <= block.timestamp) { revert NotFutureTimelock(); } IERC20 token = IERC20(tokenContract); if (token.balanceOf(msg.sender) < amount) { revert InsufficientBalance(); } if (token.allowance(msg.sender, address(this)) < amount) { revert NoAllowance(); } token.safeTransferFrom(msg.sender, address(this), amount); contractNonce+=1; commitId = bytes32(blockHashAsUint ^ contractNonce); if (hasPHTLC(commitId)) { revert CommitIdAlreadyExists(); } commitIds.push(commitId); commits[commitId] = PHTLC( dstAddress, dstChain, dstAsset, srcAsset, payable(msg.sender), payable(srcReceiver), timelock, amount, messenger, tokenContract, false, false ); emit TokenCommitted( commitId, hopChains, hopAssets, hopAddresses, dstChain, dstAddress, dstAsset, msg.sender, srcReceiver, srcAsset, amount, timelock, messenger, tokenContract ); } function lockCommitment(bytes32 commitId, bytes32 hashlock) external _committed(commitId) returns (bytes32 lockId) { lockId = hashlock; if (commits[commitId].uncommitted == true) { revert AlreadyUncommitted(); } if (commits[commitId].locked == true) { revert AlreadyLocked(); } if (hasHTLC(lockId)) { revert LockAlreadyExists(); } if (msg.sender == commits[commitId].sender || msg.sender == commits[commitId].messenger) { commits[commitId].locked = true; locks[lockId] = HTLC( commits[commitId].dstAddress, commits[commitId].dstChain, commits[commitId].dstAsset, commits[commitId].srcAsset, payable(commits[commitId].sender), commits[commitId].srcReceiver, hashlock, 0x0, commits[commitId].amount, commits[commitId].timelock, commits[commitId].tokenContract, false, false ); lockIds.push(hashlock); emit TokenLocked( hashlock, commits[commitId].dstChain, commits[commitId].dstAddress, commits[commitId].dstAsset, commits[commitId].sender, commits[commitId].srcReceiver, commits[commitId].srcAsset, commits[commitId].amount, commits[commitId].timelock, commits[commitId].messenger, commitId, commits[commitId].tokenContract ); } else { revert NoAllowance(); } } /** * @dev Sender / Payer sets up a new hash time lock contract depositing the * funds and providing the reciever and terms. * @param srcReceiver srcReceiver of the funds. * @param hashlock A sha-256 hash hashlock. * @param timelock UNIX epoch seconds time that the lock expires at. * unlocks can be made after this time. * @return lockId Id of the new HTLC. This is needed for subsequent * calls. */ function lock( bytes32 hashlock, uint256 timelock, address srcReceiver, string memory srcAsset, string memory dstChain, string memory dstAddress, string memory dstAsset, bytes32 commitId, address messenger, uint256 amount, address tokenContract ) external returns (bytes32 lockId) { if (timelock <= block.timestamp) { revert NotFutureTimelock(); } if (amount == 0) { revert FundsNotSent(); } lockId = hashlock; if (hasHTLC(lockId)) { revert LockAlreadyExists(); } IERC20 token = IERC20(tokenContract); if (token.balanceOf(msg.sender) < amount) { revert InsufficientBalance(); } if (token.allowance(msg.sender, address(this)) < amount) { revert NoAllowance(); } token.safeTransferFrom(msg.sender, address(this), amount); locks[lockId] = HTLC( dstAddress, dstChain, dstAsset, srcAsset, payable(msg.sender), payable(srcReceiver), hashlock, 0x0, amount, timelock, tokenContract, false, false ); lockIds.push(hashlock); commitIdToLockId[commitId] = lockId; emit TokenLocked( hashlock, dstChain, dstAddress, dstAsset, msg.sender, srcReceiver, srcAsset, amount, timelock, messenger, commitId, tokenContract ); if (messenger != address(0)) { uint256 codeSize; assembly { codeSize := extcodesize(messenger) } if (codeSize > 0) { try IMessenger(messenger).notify( commitId, hashlock, dstChain, dstAsset, dstAddress, srcAsset, payable(msg.sender), payable(srcReceiver), amount, timelock, tokenContract ) { // Notify successful } catch Error(string memory reason) { revert(reason); } catch (bytes memory lowLevelData) { emit LowLevelErrorOccurred(lowLevelData); revert('IMessenger notify failed'); } } else { revert NoMessenger(); } } } /** * @dev Called by the srcReceiver once they know the secret of the hashlock. * This will transfer the locked funds to their address. * * @param lockId Id of the HTLC. * @param secret sha256(secret) should equal the contract hashlock. * @return bool true on success */ function redeem(bytes32 lockId, uint256 secret) external _locked(lockId) returns (bool) { HTLC storage htlc = locks[lockId]; if (htlc.hashlock != sha256(abi.encodePacked(secret))) revert HashlockNotMatch(); if (htlc.redeemed) revert AlreadyRedeemed(); if (htlc.unlocked) revert AlreadyUnlocked(); htlc.secret = secret; htlc.redeemed = true; IERC20(htlc.tokenContract).safeTransfer(htlc.srcReceiver, htlc.amount); emit TokenRedeemed(lockId, msg.sender); return true; } /** * @dev Called by the sender if there was no redeem AND the time lock has * expired. This will unlock the contract amount. * @param lockId Id of HTLC to unlock from. * @return bool true on success */ function unlock(bytes32 lockId) external _locked(lockId) returns (bool) { HTLC storage htlc = locks[lockId]; if (htlc.unlocked) revert AlreadyUnlocked(); if (htlc.redeemed) revert AlreadyRedeemed(); if (htlc.timelock > block.timestamp) revert NotPassedTimelock(); htlc.unlocked = true; IERC20(htlc.tokenContract).safeTransfer(htlc.sender, htlc.amount); emit TokenUnlocked(lockId); return true; } function uncommit(bytes32 commitId) external _committed(commitId) returns (bool) { PHTLC storage phtlc = commits[commitId]; if (phtlc.uncommitted) revert AlreadyUncommitted(); if (phtlc.locked) revert AlreadyLocked(); if (phtlc.timelock > block.timestamp) revert NotPassedTimelock(); phtlc.uncommitted = true; IERC20(phtlc.tokenContract).safeTransfer(phtlc.sender, phtlc.amount); emit TokenUncommitted(commitId); return true; } /** * @dev Get contract details. * @param lockId HTLC contract id */ function getLockDetails(bytes32 lockId) external view returns (HTLC memory) { if (hasHTLC(lockId) == false) { HTLC memory emptyHTLC = HTLC({ dstAddress: '', dstChain: '', dstAsset: '', srcAsset: '', sender: payable(address(0)), srcReceiver: payable(address(0)), hashlock: bytes32(0x0), secret: uint256(0), amount: uint256(0), timelock: uint256(0), tokenContract: address(0), redeemed: false, unlocked: false }); return emptyHTLC; } HTLC storage htlc = locks[lockId]; return htlc; } function getCommitDetails(bytes32 commitId) public view returns (PHTLC memory) { if (!hasPHTLC(commitId)) { PHTLC memory empyPHTLC = PHTLC({ dstAddress: '', dstChain: '', dstAsset: '', srcAsset: '', sender: payable(address(0)), srcReceiver: payable(address(0)), timelock: uint256(0), amount: uint256(0), messenger: address(0), tokenContract: address(0), locked: false, uncommitted: false }); return empyPHTLC; } PHTLC storage phtlc = commits[commitId]; return phtlc; } /** * @dev Check if there is a contract with a given id. * @param lockId Id into locks mapping. */ function hasHTLC(bytes32 lockId) internal view returns (bool exists) { exists = (locks[lockId].sender != address(0)); } function hasPHTLC(bytes32 commitId) internal view returns (bool exists) { exists = (commits[commitId].sender != address(0)); } function getLocks(address senderAddr) public view returns (bytes32[] memory) { uint count = 0; for (uint i = 0; i < lockIds.length; i++) { HTLC memory htlc = locks[lockIds[i]]; if (htlc.sender == senderAddr) { count++; } } bytes32[] memory result = new bytes32[](count); uint j = 0; for (uint i = 0; i < lockIds.length; i++) { if (locks[lockIds[i]].sender == senderAddr) { result[j] = lockIds[i]; j++; } } return result; } function getCommits(address senderAddr) public view returns (bytes32[] memory) { uint count = 0; for (uint i = 0; i < commitIds.length; i++) { PHTLC memory phtlc = commits[commitIds[i]]; if (phtlc.sender == senderAddr) { count++; } } bytes32[] memory result = new bytes32[](count); uint j = 0; for (uint i = 0; i < commitIds.length; i++) { if (commits[commitIds[i]].sender == senderAddr) { result[j] = commitIds[i]; j++; } } return result; } function getLockIdByCommitId(bytes32 commitId) public view returns (bytes32) { return commitIdToLockId[commitId]; } }
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
@openzeppelin/contracts/utils/Address.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
Compiler Settings
{"viaIR":true,"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{},"evmVersion":"paris"}
Contract ABI
[{"type":"error","name":"AddressEmptyCode","inputs":[{"type":"address","name":"target","internalType":"address"}]},{"type":"error","name":"AddressInsufficientBalance","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"error","name":"AlreadyLocked","inputs":[]},{"type":"error","name":"AlreadyRedeemed","inputs":[]},{"type":"error","name":"AlreadyUncommitted","inputs":[]},{"type":"error","name":"AlreadyUnlocked","inputs":[]},{"type":"error","name":"CommitIdAlreadyExists","inputs":[]},{"type":"error","name":"CommitmentNotExists","inputs":[]},{"type":"error","name":"FailedInnerCall","inputs":[]},{"type":"error","name":"FundsNotSent","inputs":[]},{"type":"error","name":"HashlockNotMatch","inputs":[]},{"type":"error","name":"IncorrectData","inputs":[]},{"type":"error","name":"InsufficientBalance","inputs":[]},{"type":"error","name":"LockAlreadyExists","inputs":[]},{"type":"error","name":"LockNotExists","inputs":[]},{"type":"error","name":"NoAllowance","inputs":[]},{"type":"error","name":"NoMessenger","inputs":[]},{"type":"error","name":"NotFutureTimelock","inputs":[]},{"type":"error","name":"NotPassedTimelock","inputs":[]},{"type":"error","name":"SafeERC20FailedOperation","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"event","name":"LowLevelErrorOccurred","inputs":[{"type":"bytes","name":"lowLevelData","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"TokenCommitted","inputs":[{"type":"bytes32","name":"commitId","internalType":"bytes32","indexed":false},{"type":"string[]","name":"hopChains","internalType":"string[]","indexed":false},{"type":"string[]","name":"hopAssets","internalType":"string[]","indexed":false},{"type":"string[]","name":"hopAddresses","internalType":"string[]","indexed":false},{"type":"string","name":"dstChain","internalType":"string","indexed":false},{"type":"string","name":"dstAddress","internalType":"string","indexed":false},{"type":"string","name":"dstAsset","internalType":"string","indexed":false},{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"address","name":"srcReceiver","internalType":"address","indexed":false},{"type":"string","name":"srcAsset","internalType":"string","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"timelock","internalType":"uint256","indexed":false},{"type":"address","name":"messenger","internalType":"address","indexed":false},{"type":"address","name":"tokenContract","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"TokenLocked","inputs":[{"type":"bytes32","name":"hashlock","internalType":"bytes32","indexed":true},{"type":"string","name":"dstChain","internalType":"string","indexed":false},{"type":"string","name":"dstAddress","internalType":"string","indexed":false},{"type":"string","name":"dstAsset","internalType":"string","indexed":false},{"type":"address","name":"sender","internalType":"address","indexed":true},{"type":"address","name":"srcReceiver","internalType":"address","indexed":true},{"type":"string","name":"srcAsset","internalType":"string","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"timelock","internalType":"uint256","indexed":false},{"type":"address","name":"messenger","internalType":"address","indexed":false},{"type":"bytes32","name":"commitId","internalType":"bytes32","indexed":false},{"type":"address","name":"tokenContract","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"TokenRedeemed","inputs":[{"type":"bytes32","name":"lockId","internalType":"bytes32","indexed":true},{"type":"address","name":"redeemAddress","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"TokenUncommitted","inputs":[{"type":"bytes32","name":"commitId","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"TokenUnlocked","inputs":[{"type":"bytes32","name":"lockId","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"payable","outputs":[{"type":"bytes32","name":"commitId","internalType":"bytes32"}],"name":"commit","inputs":[{"type":"string[]","name":"hopChains","internalType":"string[]"},{"type":"string[]","name":"hopAssets","internalType":"string[]"},{"type":"string[]","name":"hopAddresses","internalType":"string[]"},{"type":"string","name":"dstChain","internalType":"string"},{"type":"string","name":"dstAsset","internalType":"string"},{"type":"string","name":"dstAddress","internalType":"string"},{"type":"string","name":"srcAsset","internalType":"string"},{"type":"address","name":"srcReceiver","internalType":"address"},{"type":"uint256","name":"timelock","internalType":"uint256"},{"type":"address","name":"messenger","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"tokenContract","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct HashedTimeLockERC20.PHTLC","components":[{"type":"string","name":"dstAddress","internalType":"string"},{"type":"string","name":"dstChain","internalType":"string"},{"type":"string","name":"dstAsset","internalType":"string"},{"type":"string","name":"srcAsset","internalType":"string"},{"type":"address","name":"sender","internalType":"address payable"},{"type":"address","name":"srcReceiver","internalType":"address payable"},{"type":"uint256","name":"timelock","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"messenger","internalType":"address"},{"type":"address","name":"tokenContract","internalType":"address"},{"type":"bool","name":"locked","internalType":"bool"},{"type":"bool","name":"uncommitted","internalType":"bool"}]}],"name":"getCommitDetails","inputs":[{"type":"bytes32","name":"commitId","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32[]","name":"","internalType":"bytes32[]"}],"name":"getCommits","inputs":[{"type":"address","name":"senderAddr","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct HashedTimeLockERC20.HTLC","components":[{"type":"string","name":"dstAddress","internalType":"string"},{"type":"string","name":"dstChain","internalType":"string"},{"type":"string","name":"dstAsset","internalType":"string"},{"type":"string","name":"srcAsset","internalType":"string"},{"type":"address","name":"sender","internalType":"address payable"},{"type":"address","name":"srcReceiver","internalType":"address payable"},{"type":"bytes32","name":"hashlock","internalType":"bytes32"},{"type":"uint256","name":"secret","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"timelock","internalType":"uint256"},{"type":"address","name":"tokenContract","internalType":"address"},{"type":"bool","name":"redeemed","internalType":"bool"},{"type":"bool","name":"unlocked","internalType":"bool"}]}],"name":"getLockDetails","inputs":[{"type":"bytes32","name":"lockId","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getLockIdByCommitId","inputs":[{"type":"bytes32","name":"commitId","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32[]","name":"","internalType":"bytes32[]"}],"name":"getLocks","inputs":[{"type":"address","name":"senderAddr","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes32","name":"lockId","internalType":"bytes32"}],"name":"lock","inputs":[{"type":"bytes32","name":"hashlock","internalType":"bytes32"},{"type":"uint256","name":"timelock","internalType":"uint256"},{"type":"address","name":"srcReceiver","internalType":"address"},{"type":"string","name":"srcAsset","internalType":"string"},{"type":"string","name":"dstChain","internalType":"string"},{"type":"string","name":"dstAddress","internalType":"string"},{"type":"string","name":"dstAsset","internalType":"string"},{"type":"bytes32","name":"commitId","internalType":"bytes32"},{"type":"address","name":"messenger","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"tokenContract","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes32","name":"lockId","internalType":"bytes32"}],"name":"lockCommitment","inputs":[{"type":"bytes32","name":"commitId","internalType":"bytes32"},{"type":"bytes32","name":"hashlock","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"redeem","inputs":[{"type":"bytes32","name":"lockId","internalType":"bytes32"},{"type":"uint256","name":"secret","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"uncommit","inputs":[{"type":"bytes32","name":"commitId","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"unlock","inputs":[{"type":"bytes32","name":"lockId","internalType":"bytes32"}]}]
Contract Creation Code
0x6080806040523461004557600019430143811161002f574080600555600655600060075561310f908161004b8239f35b634e487b7160e01b600052601160045260246000fd5b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c8063255f3154146125d45780632ea3b73c1461240e578063392d642414611c3d57806339e3527114611c135780633b9c1f5b14611b1c5780636552b7421461102e578063673da15414610ee6578063719f308914610d10578063dcc19d59146102bb578063ec9b5b3a146101b35763f5a1862a1461009657600080fd5b346101b05760203660031901126101b057600435906100cd82600052600160205260018060a01b0360046040600020015416151590565b1561019e578181526001602052604081209160098301805460ff8160a81c1661018c5760ff8160a01c1661017a57600685015442106101685760ff60a81b198116600160a81b17909155600484015460079094015460209461013b926001600160a01b039182169116612fa9565b7fa123e15752679aa06522e49c50e26d336ea83e1aa2e8ecdc4a32f437a474d1366040519280a260018152f35b60405163b3f711f760e01b8152600490fd5b6040516317c3335f60e21b8152600490fd5b604051630e4a482d60e11b8152600490fd5b604051630bfa77dd60e41b8152600490fd5b80fd5b50346101b05760203660031901126101b057600435906101eb82600052600060205260018060a01b0360046040600020015416151590565b156102a957818152806020526040812091600a8301805460ff8160a81c166102975760ff8160a01c1661028557600985015442106101685760ff60a81b198116600160a81b179091556004840154600890940154602094610258926001600160a01b039182169116612fa9565b7f3d4cedda486476ed25b0bd452211f1c4b1af03b25ad9d223a96238f84ce640f46040519280a260018152f35b6040516306d3830f60e21b8152600490fd5b6040516328486b6360e11b8152600490fd5b604051632254ea3d60e11b8152600490fd5b506101803660031901126101b0576004356001600160401b038111610d0c576102e8903690600401612813565b6024356001600160401b038111610d0857610307903690600401612813565b906044356001600160401b038111610d0457610327903690600401612813565b6064356001600160401b038111610d00576103469036906004016127b5565b6084356001600160401b038111610cfc576103659036906004016127b5565b9060a4356001600160401b038111610cf8576103859036906004016127b5565b9160c4356001600160401b038111610cf4576103a59036906004016127b5565b9260e435926001600160a01b0384168403610c745761012435956001600160a01b0387168703610c7457610164356001600160a01b0381169003610c74576101443515610ce25742610104351115610cd0576040516370a0823160e01b8152336004820152602081602481610164356001600160a01b03165afa908115610c81578b91610c9e575b506101443511610c8c57604051636eb1769f60e11b81523360048201523060248201526020816044816001600160a01b0361016435165afa908115610c81578b91610c4a575b506101443511610c3857610498610144353033610164356001600160a01b0316612f4f565b60075460018101809111610c2457600781905560065418600081815260016020526040902060040154909a906001600160a01b0316610c1257600454600160401b811015610bfc5761050b6104f48260018f9401600455612b5d565b819391549060031b91821b91600019901b19161790565b905560405161051981612726565b84815260208082018590526040808301889052606083018a90523360808401526001600160a01b0389811660a08501526101043560c08501526101443560e08501528b81166101008501526101643516610120840152610140830184905261016083018490528d84526001909152822081518051919391906001600160401b038211610a5b5781906105ab8654612892565b601f8111610bae575b50602090601f8311600114610b45578492610b3a575b50508160011b916000199060031b1c19161783555b60208201518051906001600160401b038211610a5b5781906106046001870154612892565b601f8111610ae9575b50602090601f8311600114610a7a578492610a6f575b50508160011b916000199060031b1c19161760018401555b60408201518051906001600160401b038211610a5b5781906106606002870154612892565b601f8111610a0a575b50602090601f831160011461099b578492610990575b50508160011b916000199060031b1c19161760028401555b6060820151908151916001600160401b03831161097c579082916106be6003870154612892565b601f8111610926575b50602091601f84116001146108b757926108ac575b50508160011b916000199060031b1c19161760038301555b60808101516004830180546001600160a01b03199081166001600160a01b039384161790915560a083810151600586018054841691851691909117905560c0840151600686015560e0840151600786015561010084015160088601805490931690841617909155610120830151600990940180546101408501516001600160a81b03199091169590931694909417911515901b60ff60a01b161782556101600151815460ff60a81b191690151560a81b60ff60a81b161790556040519889986101c08c8b528060208c01528a016107ca91612ef2565b89810360408b01526107db91612ef2565b88810360608a01526107ec91612ef2565b87810360808901526107fd916126af565b86810360a088015261080e916126af565b85810360c087015261081f916126af565b3360e08601526001600160a01b03909116610100850152838103610120850152610848916126af565b61014435610140840152610104356101608401526001600160a01b03918216610180840152610164359091166101a08301527f39aa705c04023f1efa19bdc0767577e0092740a3754926bb71c98869b20000239291900390a1604051908152602090f35b0151905038806106dc565b6003870181526020812090945091905b601f198416851061090b576001945083601f198116106108f2575b505050811b0160038301556106f4565b015160001960f88460031b161c191690553880806108e2565b818101518355602094850194600190930192909101906108c7565b9091925060038601835260208320601f850160051c81019160208610610972575b90601f86959493920160051c01905b81811061096357506106c7565b60008155859450600101610956565b9091508190610947565b634e487b7160e01b82526041600452602482fd5b01519050388061067f565b9250600286018452602084209084935b601f19841685106109ef576001945083601f198116106109d6575b505050811b016002840155610697565b015160001960f88460031b161c191690553880806109c6565b818101518355602094850194600190930192909101906109ab565b90915060028601845260208420601f840160051c810160208510610a54575b90849392915b601f830160051c82018110610a45575050610669565b60008155859450600101610a2f565b5080610a29565b634e487b7160e01b83526041600452602483fd5b015190503880610623565b9250600186018452602084209084935b601f1984168510610ace576001945083601f19811610610ab5575b505050811b01600184015561063b565b015160001960f88460031b161c19169055388080610aa5565b81810151835560209485019460019093019290910190610a8a565b90915060018601845260208420601f840160051c810160208510610b33575b90849392915b601f830160051c82018110610b2457505061060d565b60008155859450600101610b0e565b5080610b08565b0151905038806105ca565b9250858452602084209084935b601f1984168510610b93576001945083601f19811610610b7a575b505050811b0183556105df565b015160001960f88460031b161c19169055388080610b6d565b81810151835560209485019460019093019290910190610b52565b90915085845260208420601f840160051c810160208510610bf5575b90849392915b601f830160051c82018110610be65750506105b4565b60008155859450600101610bd0565b5080610bca565b634e487b7160e01b600052604160045260246000fd5b604051637870919b60e01b8152600490fd5b634e487b7160e01b8b52601160045260248bfd5b604051631d7eb35960e31b8152600490fd5b90506020813d602011610c79575b81610c6560209383612779565b81010312610c74575138610473565b600080fd5b3d9150610c58565b6040513d8d823e3d90fd5b604051631e9acf1760e31b8152600490fd5b90506020813d602011610cc8575b81610cb960209383612779565b81010312610c7457513861042d565b3d9150610cac565b604051633dd8280960e21b8152600490fd5b604051636f8ab38d60e11b8152600490fd5b8780fd5b8680fd5b8580fd5b8480fd5b8380fd5b8280fd5b5080fd5b50346101b057602080600319360112610d0c57610d2b6126d4565b600380549290916001600160a01b039081169085805b868110610dcb5750610d5290612c06565b958093815b878110610d705760405180610d6c8b826126ea565b0390f35b610d7981612baa565b905490881b1c8352828252848460046040862001541614610d9d575b600101610d57565b94610dc3600191610dad88612baa565b9054908a1b1c610dbd828d612c38565b52612be1565b959050610d95565b610dd481612baa565b905490871b1c88528785528360408920604051610df081612742565b604051610e0881610e0181866128cc565b0382612779565b8152604051610e1e81610e0181600187016128cc565b88820152604051610e3681610e0181600287016128cc565b6040820152604051610e4e81610e01818d87016128cc565b60608201526101808660048401541692836080840152600a886005830154169160a09283860152600681015460c0860152600781015460e0860152600881015461010086015260098101546101208601520154809189821661014086015260ff9283911c16151561016085015260a81c16151591015214610ed2575b600101610d41565b90610ede600191612be1565b919050610eca565b50346101b05760403660031901126101b057600435602435610f2082600052600060205260018060a01b0360046040600020015416151590565b156102a9578183526020928084526040812090600682015490604051868101858152878252604082018281106001600160401b03821117610bfc57889281610f71869482604052835192839161268c565b8101039060025afa1561102257510361101057600a81019081549160ff8360a01c166102855760ff8360a81c1661029757600782019390935560ff60a01b198216600160a01b179092556005820154600890920154610fde9290916001600160a01b039182169116612fa9565b7f0f7c50d316885e5d3719752f760bbbbf7d56363501e721eea4d913e255b632e482604051338152a260405160018152f35b60405163e73bcb3560e01b8152600490fd5b604051903d90823e3d90fd5b50346101b0576101603660031901126101b057604435906001600160a01b03821682036101b0576064356001600160401b038111610d0c576110749036906004016127b5565b916084356001600160401b038111610d08576110949036906004016127b5565b9060a4356001600160401b038111610d04576110b49036906004016127b5565b60c4356001600160401b038111610d00576110d39036906004016127b5565b94610104356001600160a01b0381169003610d005761014435916001600160a01b0383168303610cfc57426024351115610cd0576101243515610ce25760048035600090815260208190526040902001546001600160a01b0316611b0a576040516370a0823160e01b81523360048201526020816024816001600160a01b0388165afa908115611acd578791611ad8575b506101243511610c8c57604051636eb1769f60e11b81523360048201523060248201526020816044816001600160a01b0388165afa908115611acd578791611a9b575b506101243511610c38576111c96101243530336001600160a01b038716612f4f565b6040516111d581612742565b81815285602082015287604082015282606082015233608082015260018060a01b03851660a082015260043560c08201528660e08201526101243561010082015260243561012082015260018060a01b0384166101408201528661016082015286610180820152600435875286602052604087209080518051906001600160401b03821161182f5781906112698554612892565b601f8111611a4d575b50602090601f83116001146119e4578b926119d9575b50508160011b916000199060031b1c19161782555b60208101518051906001600160401b03821161182f5781906112c26001860154612892565b601f8111611988575b50602090601f8311600114611919578b9261190e575b50508160011b916000199060031b1c19161760018301555b60408101518051906001600160401b03821161182f57819061131e6002860154612892565b601f81116118bd575b50602090601f831160011461184e578b92611843575b50508160011b916000199060031b1c19161760028301555b60608101518051906001600160401b03821161182f576113786003850154612892565b601f81116117ea575b50602090601f8311600114611775579180611474959492610180948d9261176a575b50508160011b916000199060031b1c19161760038401555b60808101516004840180546001600160a01b03199081166001600160a01b039384161790915560a0838101516005870180549093169084161790915560c0830151600686015560e0830151600786015561010083015160088601556101208301516009860155610140830151600a9590950180546101608501516001600160a81b03199091169690931695909517911515901b60ff60a01b161783555b0151815460ff60a81b191690151560a81b60ff60a81b16179055565b61147f600435612c4c565b60e43586526002602052600435604087205560405161012081526114da6114cc6114be6114b061012085018a6126af565b8481036020860152856126af565b83810360408501528a6126af565b8281036060840152846126af565b61012435608083015260243560a08301526001600160a01b0361010435811660c084015260e43560e08401528581166101008401528616913391600435917fe00962102cab6d15d8733bbc057ea3d34381c044904c4312bfdf966c2d11589a9181900390a4610104356001600160a01b031661155d575b60206040516004358152f35b610104353b1561175857610104356001600160a01b03163b15610cfc57916115f76115c194926115e58897956115d36040519b8c998a99635e863a5b60e01b8b5260e43560048c015260043560248c015261016060448c01526101648b01906126af565b8981036003190160648b0152906126af565b878103600319016084890152906126af565b8581036003190160a4870152906126af565b913360c485015260018060a01b031660e48401526101243561010484015260243561012484015260018060a01b031661014483015203818360018060a01b0361010435165af19182611741575b5090611734578060033d11611723575b506308c379a0146116e8575b7f7b5bdb2f87e8e20f082bba9be5f7e870728f9bba18540559ccdcdcbb1fc5a0876116a061168c612ec2565b6040519182916020835260208301906126af565b0390a160405162461bcd60e51b815260206004820152601860248201527f494d657373656e676572206e6f74696679206661696c656400000000000000006044820152606490fd5b6116f0612e51565b806116fb5750611660565b60405162461bcd60e51b81526020600482015290819061171f9060248301906126af565b0390fd5b9050600481803e5160e01c38611654565b5038808080808080611551565b6001600160401b03811161097c5760405238611644565b604051633127e9d760e11b8152600490fd5b0151905038806113a3565b90600385018b5260208b20918b5b601f19851681106117d25750926114749594926001926101809583601f198116106117b9575b505050811b0160038401556113bb565b015160001960f88460031b161c191690553880806117a9565b91926020600181928685015181550194019201611783565b600385018b5260208b20601f840160051c810160208510611828575b8c601f840160051c8301821061181e57505050611381565b8155600101611806565b5080611806565b634e487b7160e01b8a52604160045260248afd5b01519050388061133d565b9250600285018b5260208b20908b935b601f19841685106118a2576001945083601f19811610611889575b505050811b016002830155611355565b015160001960f88460031b161c19169055388080611879565b8181015183556020948501946001909301929091019061185e565b909150600285018b5260208b20601f840160051c810160208510611907575b90849392915b8d601f840160051c830182106118fa57505050611327565b81558594506001016118e2565b50806118dc565b0151905038806112e1565b9250600185018b5260208b20908b935b601f198416851061196d576001945083601f19811610611954575b505050811b0160018301556112f9565b015160001960f88460031b161c19169055388080611944565b81810151835560209485019460019093019290910190611929565b909150600185018b5260208b20601f840160051c8101602085106119d2575b90849392915b8d601f840160051c830182106119c5575050506112cb565b81558594506001016119ad565b50806119a7565b015190503880611288565b9250848b5260208b20908b935b601f1984168510611a32576001945083601f19811610611a19575b505050811b01825561129d565b015160001960f88460031b161c19169055388080611a0c565b818101518355602094850194600190930192909101906119f1565b909150848b5260208b20601f840160051c810160208510611a94575b90849392915b8d601f840160051c83018210611a8757505050611272565b8155859450600101611a6f565b5080611a69565b90506020813d602011611ac5575b81611ab660209383612779565b81010312610cf85751386111a7565b3d9150611aa9565b6040513d89823e3d90fd5b90506020813d602011611b02575b81611af360209383612779565b81010312610cf8575138611164565b3d9150611ae6565b60405163748d150960e01b8152600490fd5b50346101b05760203660031901126101b057611b39600435612c72565b6040518091602082528051611ba7611b5f610180928360208701526101a08601906126af565b611b92611b7e602086015192601f1993848983030160408a01526126af565b6040860151838883030160608901526126af565b906060850151908683030160808701526126af565b91608081015160018060a01b0380911660a08601528060a08301511660c086015260c082015160e086015260e082015161010090818701528201518161012091168187015282015190610140911681860152810151906101609115158286015201511515908301520390f35b50346101b05760203660031901126101b05760406020916004358152600283522054604051908152f35b50346101b05760403660031901126101b05760048035600090815260016020526040902001546001600160a01b03161561019e5760043581526001602052600160ff600960408420015460a81c1615151461018c5760043581526001602052600160ff600960408420015460a01c1615151461017a576024356000908152602081905260409020600401546001600160a01b0316611b0a57600435815260016020526040812060018060a01b0360048201541633149081156123f7575b5015610c38576004803582526001602052604080832060098101805460ff60a01b198116600160a01b179091559281015460058201546007830154600684015494519695949390926001600160a01b03928316921690600390611db590611d608a612742565b604051611d7181610e0181856128cc565b8a52604051611d8781610e0181600186016128cc565b60208b0152604051611da081610e0181600286016128cc565b60408b0152610e0160405180948193016128cc565b6060880152608087015260a086015260243560c08601528360e086015261010085015261012084015260018060a01b031661014083015280610160830152806101808301526024358152806020526040812082519283516001600160401b0381116121bb57611e248354612892565b601f81116123b6575b506020601f82116001146123505784958293949592612345575b50508160011b916000199060031b1c19161782555b60208101519283516001600160401b03811161097c57611e7f6001850154612892565b601f8111612301575b506020601f8211600114612295578293949582939261228a575b50508160011b916000199060031b1c19161760018401555b60408201519283516001600160401b038111610a5b57611edd6002830154612892565b601f8111612246575b506020601f82116001146121da57839495829394926121cf575b50508160011b916000199060031b1c19161760028201555b60608301519283516001600160401b0381116121bb57611f3b6003840154612892565b601f8111612177575b506020601f821160011461211b5791816101809261201e9594604098889261176a5750508160011b916000199060031b1c191617600384015560808101516004840180546001600160a01b03199081166001600160a01b039384161790915560a0838101516005870180549093169084161790915560c0830151600686015560e0830151600786015561010083015160088601556101208301516009860155610140830151600a9590950180546101608501516001600160a81b03199091169690931695909517911515901b60ff60a01b16178355611458565b612029602435612c4c565b600435815260016020522060018060a01b0360048201541660018060a01b03600583015416917fe00962102cab6d15d8733bbc057ea3d34381c044904c4312bfdf966c2d11589a600782015491600681015460018060a01b0360088301541660018060a01b03600984015416916120e960405194610120865260036120da6120c96120bb6101208a01600186016128cc565b89810360208b0152846128cc565b88810360408a0152600284016128cc565b918783036060890152016128cc565b95608085015260a084015260c083015260043560e083015261010082015280602435930390a460206040516024358152f35b6003840185526020852095855b601f198416811061215f57508260409761201e96959360019361018096601f198116106117b957505050811b0160038401556113bb565b82820151885560019097019660209283019201612128565b60038401855260208520601f830160051c8101602084106121b4575b601f830160051c820181106121a9575050611f44565b868155600101612193565b5080612193565b634e487b7160e01b84526041600452602484fd5b015190503880611f00565b6002830184526020842090845b601f198416811061222e575060019394959683601f19811610612215575b505050811b016002820155611f18565b015160001960f88460031b161c19169055388080612205565b9091602060018192858b0151815501930191016121e7565b60028301845260208420601f830160051c810160208410612283575b601f830160051c82018110612278575050611ee6565b858155600101612262565b5080612262565b015190503880611ea2565b6001850183526020832090835b601f19841681106122e9575060019394959683601f198116106122d0575b505050811b016001840155611eba565b015160001960f88460031b161c191690553880806122c0565b9091602060018192858b0151815501930191016122a2565b60018501835260208320601f830160051c81016020841061233e575b601f830160051c82018110612333575050611e88565b84815560010161231d565b508061231d565b015190503880611e47565b8385526020852090855b601f198416811061239e575060019394959683601f19811610612385575b505050811b018255611e5c565b015160001960f88460031b161c19169055388080612378565b9091602060018192858b01518155019301910161235a565b83855260208520601f830160051c8101602084106123f0575b601f830160051c820181106123e5575050611e2d565b8681556001016123cf565b50806123cf565b600801546001600160a01b03163314905038611cfa565b50346101b05760209060206003193601126101b05761242b6126d4565b6004546001600160a01b039390929091841681805b8581106124c2575061245190612c06565b9482805b86811061246a5760405180610d6c8a826126ea565b61247381612b5d565b9054600391821b1c83526001875284846004604086200154161461249b575b50600101612455565b81956124bb916124ac600194612b5d565b9054911b1c610dbd828c612c38565b9490612492565b826124cc82612b5d565b9054600391821b1c86526001808852610e016125456040892093610e0161251a604051956124f987612726565b60405161250a81610e01818c6128cc565b8752604051928380928a016128cc565b8b85015260405161253281610e018160028a016128cc565b60408501526040519283809287016128cc565b60608201526101608a6004840154169283608084015260098c6005830154169160a09283860152600681015460c0860152600781015460e08601528d600882015416610100860152015480918d821661012086015260ff9283911c16151561014085015260a81c161515910152146125c0575b600101612440565b906125cc600191612be1565b9190506125b8565b50346101b05760203660031901126101b0576125f1600435612962565b6040518091602082528051612617611b5f6101a0928360208701526101c08601906126af565b91608081015160018060a01b0380911660a08601528060a08301511660c086015260c082015160e086015260e082015161010090818701528201516101209081870152820151610140908187015282015190610160911681860152810151906101809115158286015201511515908301520390f35b60005b83811061269f5750506000910152565b818101518382015260200161268f565b906020916126c88151809281855285808601910161268c565b601f01601f1916010190565b600435906001600160a01b0382168203610c7457565b602090602060408183019282815285518094520193019160005b828110612712575050505090565b835185529381019392810192600101612704565b61018081019081106001600160401b03821117610bfc57604052565b6101a081019081106001600160401b03821117610bfc57604052565b602081019081106001600160401b03821117610bfc57604052565b90601f801991011681019081106001600160401b03821117610bfc57604052565b6001600160401b038111610bfc57601f01601f191660200190565b81601f82011215610c74578035906127cc8261279a565b926127da6040519485612779565b82845260208383010111610c7457816000926020809301838601378301015290565b6001600160401b038111610bfc5760051b60200190565b81601f82011215610c745780359160209161282d846127fc565b9361283b6040519586612779565b808552838086019160051b83010192808411610c7457848301915b8483106128665750505050505090565b82356001600160401b038111610c74578691612887848480948901016127b5565b815201920191612856565b90600182811c921680156128c2575b60208310146128ac57565b634e487b7160e01b600052602260045260246000fd5b91607f16916128a1565b8054600093926128db82612892565b918282526020936001916001811690816000146129435750600114612902575b5050505050565b90939495506000929192528360002092846000945b83861061292f575050505001019038808080806128fb565b805485870183015294019385908201612917565b60ff19168685015250505090151560051b0101915038808080806128fb565b604090815161297081612742565b606091828252826020830152828483015282808301526000908160808401528160a08401528160c08401528160e08401526101009180838501526101209481868601528661014092808488015261016094818689015281610180809901526129f081600052600060205260018060a01b0360046040600020015416151590565b15612ad8578152602081905220875197959660ff96600a9390612a128b612742565b8051612a2281610e0181886128cc565b8b528051612a3781610e0181600189016128cc565b60208c01528051612a4f81610e0181600289016128cc565b818c01525190612a6d82612a6681600388016128cc565b0383612779565b8a015260018060a01b03958660048401541660808b01528660058401541660a08b0152600683015460c08b0152600783015460e08b01526008830154908a0152600982015490890152015492831690860152828260a01c1615159085015260a81c1615159082015290565b50968780968195948294519b612aed8d612742565b8051612af88161275e565b8481528d52805160208e612b0b8361275e565b86835201528051818e612b1d8361275e565b86835201525190612b2d8261275e565b8382528c01528160808c01528160a08c01528160c08c01528160e08c01528a015288015286015284015282015290565b600454811015612b945760046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b0190600090565b634e487b7160e01b600052603260045260246000fd5b600354811015612b945760036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0190600090565b6000198114612bf05760010190565b634e487b7160e01b600052601160045260246000fd5b90612c10826127fc565b612c1d6040519182612779565b8281528092612c2e601f19916127fc565b0190602036910137565b8051821015612b945760209160051b010190565b600354600160401b811015610bfc576104f4816001612c6e9301600355612baa565b9055565b6040908151612c8081612726565b6060808252806020830152808483015280808301526000928360808401528360a08401528360c08401528360e0840152610100918483850152610120908582860152866101409387858801528761016080980152612cf681600052600160205260018060a01b0360046040600020015416151590565b15612dd15790876009939260ff98995260016020522090885198612d198a612726565b8051612d2981610e0181876128cc565b8a528051612d3e81610e0181600188016128cc565b60208b01528051612d5681610e0181600288016128cc565b818b01525190612d6d82612a6681600387016128cc565b89015260018060a01b03948560048301541660808a01528560058301541660a08a0152600682015460c08a0152600782015460e08a01528560088301541690890152015492831690860152828260a01c1615159085015260a81c1615159082015290565b50869485939284925199612de48b612726565b8051612def8161275e565b8481528b528051612dff8161275e565b84815260208c01528051612e128161275e565b848152818c01525190612e248261275e565b8382528a01528160808a01528160a08a01528160c08a01528160e08a015288015286015284015282015290565b600060443d10612eae57604051600319913d83016004833e81516001600160401b03918282113d602484011117612eb157818401948551938411612eb9573d85010160208487010111612eb15750612eae92910160200190612779565b90565b949350505050565b50949350505050565b3d15612eed573d90612ed38261279a565b91612ee16040519384612779565b82523d6000602084013e565b606090565b90808251908181526020809101926020808460051b8301019501936000915b848310612f215750505050505090565b9091929394958480612f3f600193601f198682030187528a516126af565b9801930193019194939290612f11565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815260a08101918183106001600160401b03841117610bfc57612fa792604052612ff4565b565b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448083019390935291815260808101916001600160401b03831182841017610bfc57612fa7926040525b60018060a01b03169061301e600080836020829551910182875af1613017612ec2565b9084613076565b90815191821515928361304e575b5050506130365750565b60249060405190635274afe760e01b82526004820152fd5b819293509060209181010312610d0c5760200151908115918215036101b0575038808061302c565b9061309d575080511561308b57805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806130d0575b6130ae575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156130a656fea264697066735822122065fe76446d5320fa47fe99efc8a0e7b17c882faa829463637a4b537195fe278764736f6c63430008170033
Deployed ByteCode
0x6080604052600436101561001257600080fd5b6000803560e01c8063255f3154146125d45780632ea3b73c1461240e578063392d642414611c3d57806339e3527114611c135780633b9c1f5b14611b1c5780636552b7421461102e578063673da15414610ee6578063719f308914610d10578063dcc19d59146102bb578063ec9b5b3a146101b35763f5a1862a1461009657600080fd5b346101b05760203660031901126101b057600435906100cd82600052600160205260018060a01b0360046040600020015416151590565b1561019e578181526001602052604081209160098301805460ff8160a81c1661018c5760ff8160a01c1661017a57600685015442106101685760ff60a81b198116600160a81b17909155600484015460079094015460209461013b926001600160a01b039182169116612fa9565b7fa123e15752679aa06522e49c50e26d336ea83e1aa2e8ecdc4a32f437a474d1366040519280a260018152f35b60405163b3f711f760e01b8152600490fd5b6040516317c3335f60e21b8152600490fd5b604051630e4a482d60e11b8152600490fd5b604051630bfa77dd60e41b8152600490fd5b80fd5b50346101b05760203660031901126101b057600435906101eb82600052600060205260018060a01b0360046040600020015416151590565b156102a957818152806020526040812091600a8301805460ff8160a81c166102975760ff8160a01c1661028557600985015442106101685760ff60a81b198116600160a81b179091556004840154600890940154602094610258926001600160a01b039182169116612fa9565b7f3d4cedda486476ed25b0bd452211f1c4b1af03b25ad9d223a96238f84ce640f46040519280a260018152f35b6040516306d3830f60e21b8152600490fd5b6040516328486b6360e11b8152600490fd5b604051632254ea3d60e11b8152600490fd5b506101803660031901126101b0576004356001600160401b038111610d0c576102e8903690600401612813565b6024356001600160401b038111610d0857610307903690600401612813565b906044356001600160401b038111610d0457610327903690600401612813565b6064356001600160401b038111610d00576103469036906004016127b5565b6084356001600160401b038111610cfc576103659036906004016127b5565b9060a4356001600160401b038111610cf8576103859036906004016127b5565b9160c4356001600160401b038111610cf4576103a59036906004016127b5565b9260e435926001600160a01b0384168403610c745761012435956001600160a01b0387168703610c7457610164356001600160a01b0381169003610c74576101443515610ce25742610104351115610cd0576040516370a0823160e01b8152336004820152602081602481610164356001600160a01b03165afa908115610c81578b91610c9e575b506101443511610c8c57604051636eb1769f60e11b81523360048201523060248201526020816044816001600160a01b0361016435165afa908115610c81578b91610c4a575b506101443511610c3857610498610144353033610164356001600160a01b0316612f4f565b60075460018101809111610c2457600781905560065418600081815260016020526040902060040154909a906001600160a01b0316610c1257600454600160401b811015610bfc5761050b6104f48260018f9401600455612b5d565b819391549060031b91821b91600019901b19161790565b905560405161051981612726565b84815260208082018590526040808301889052606083018a90523360808401526001600160a01b0389811660a08501526101043560c08501526101443560e08501528b81166101008501526101643516610120840152610140830184905261016083018490528d84526001909152822081518051919391906001600160401b038211610a5b5781906105ab8654612892565b601f8111610bae575b50602090601f8311600114610b45578492610b3a575b50508160011b916000199060031b1c19161783555b60208201518051906001600160401b038211610a5b5781906106046001870154612892565b601f8111610ae9575b50602090601f8311600114610a7a578492610a6f575b50508160011b916000199060031b1c19161760018401555b60408201518051906001600160401b038211610a5b5781906106606002870154612892565b601f8111610a0a575b50602090601f831160011461099b578492610990575b50508160011b916000199060031b1c19161760028401555b6060820151908151916001600160401b03831161097c579082916106be6003870154612892565b601f8111610926575b50602091601f84116001146108b757926108ac575b50508160011b916000199060031b1c19161760038301555b60808101516004830180546001600160a01b03199081166001600160a01b039384161790915560a083810151600586018054841691851691909117905560c0840151600686015560e0840151600786015561010084015160088601805490931690841617909155610120830151600990940180546101408501516001600160a81b03199091169590931694909417911515901b60ff60a01b161782556101600151815460ff60a81b191690151560a81b60ff60a81b161790556040519889986101c08c8b528060208c01528a016107ca91612ef2565b89810360408b01526107db91612ef2565b88810360608a01526107ec91612ef2565b87810360808901526107fd916126af565b86810360a088015261080e916126af565b85810360c087015261081f916126af565b3360e08601526001600160a01b03909116610100850152838103610120850152610848916126af565b61014435610140840152610104356101608401526001600160a01b03918216610180840152610164359091166101a08301527f39aa705c04023f1efa19bdc0767577e0092740a3754926bb71c98869b20000239291900390a1604051908152602090f35b0151905038806106dc565b6003870181526020812090945091905b601f198416851061090b576001945083601f198116106108f2575b505050811b0160038301556106f4565b015160001960f88460031b161c191690553880806108e2565b818101518355602094850194600190930192909101906108c7565b9091925060038601835260208320601f850160051c81019160208610610972575b90601f86959493920160051c01905b81811061096357506106c7565b60008155859450600101610956565b9091508190610947565b634e487b7160e01b82526041600452602482fd5b01519050388061067f565b9250600286018452602084209084935b601f19841685106109ef576001945083601f198116106109d6575b505050811b016002840155610697565b015160001960f88460031b161c191690553880806109c6565b818101518355602094850194600190930192909101906109ab565b90915060028601845260208420601f840160051c810160208510610a54575b90849392915b601f830160051c82018110610a45575050610669565b60008155859450600101610a2f565b5080610a29565b634e487b7160e01b83526041600452602483fd5b015190503880610623565b9250600186018452602084209084935b601f1984168510610ace576001945083601f19811610610ab5575b505050811b01600184015561063b565b015160001960f88460031b161c19169055388080610aa5565b81810151835560209485019460019093019290910190610a8a565b90915060018601845260208420601f840160051c810160208510610b33575b90849392915b601f830160051c82018110610b2457505061060d565b60008155859450600101610b0e565b5080610b08565b0151905038806105ca565b9250858452602084209084935b601f1984168510610b93576001945083601f19811610610b7a575b505050811b0183556105df565b015160001960f88460031b161c19169055388080610b6d565b81810151835560209485019460019093019290910190610b52565b90915085845260208420601f840160051c810160208510610bf5575b90849392915b601f830160051c82018110610be65750506105b4565b60008155859450600101610bd0565b5080610bca565b634e487b7160e01b600052604160045260246000fd5b604051637870919b60e01b8152600490fd5b634e487b7160e01b8b52601160045260248bfd5b604051631d7eb35960e31b8152600490fd5b90506020813d602011610c79575b81610c6560209383612779565b81010312610c74575138610473565b600080fd5b3d9150610c58565b6040513d8d823e3d90fd5b604051631e9acf1760e31b8152600490fd5b90506020813d602011610cc8575b81610cb960209383612779565b81010312610c7457513861042d565b3d9150610cac565b604051633dd8280960e21b8152600490fd5b604051636f8ab38d60e11b8152600490fd5b8780fd5b8680fd5b8580fd5b8480fd5b8380fd5b8280fd5b5080fd5b50346101b057602080600319360112610d0c57610d2b6126d4565b600380549290916001600160a01b039081169085805b868110610dcb5750610d5290612c06565b958093815b878110610d705760405180610d6c8b826126ea565b0390f35b610d7981612baa565b905490881b1c8352828252848460046040862001541614610d9d575b600101610d57565b94610dc3600191610dad88612baa565b9054908a1b1c610dbd828d612c38565b52612be1565b959050610d95565b610dd481612baa565b905490871b1c88528785528360408920604051610df081612742565b604051610e0881610e0181866128cc565b0382612779565b8152604051610e1e81610e0181600187016128cc565b88820152604051610e3681610e0181600287016128cc565b6040820152604051610e4e81610e01818d87016128cc565b60608201526101808660048401541692836080840152600a886005830154169160a09283860152600681015460c0860152600781015460e0860152600881015461010086015260098101546101208601520154809189821661014086015260ff9283911c16151561016085015260a81c16151591015214610ed2575b600101610d41565b90610ede600191612be1565b919050610eca565b50346101b05760403660031901126101b057600435602435610f2082600052600060205260018060a01b0360046040600020015416151590565b156102a9578183526020928084526040812090600682015490604051868101858152878252604082018281106001600160401b03821117610bfc57889281610f71869482604052835192839161268c565b8101039060025afa1561102257510361101057600a81019081549160ff8360a01c166102855760ff8360a81c1661029757600782019390935560ff60a01b198216600160a01b179092556005820154600890920154610fde9290916001600160a01b039182169116612fa9565b7f0f7c50d316885e5d3719752f760bbbbf7d56363501e721eea4d913e255b632e482604051338152a260405160018152f35b60405163e73bcb3560e01b8152600490fd5b604051903d90823e3d90fd5b50346101b0576101603660031901126101b057604435906001600160a01b03821682036101b0576064356001600160401b038111610d0c576110749036906004016127b5565b916084356001600160401b038111610d08576110949036906004016127b5565b9060a4356001600160401b038111610d04576110b49036906004016127b5565b60c4356001600160401b038111610d00576110d39036906004016127b5565b94610104356001600160a01b0381169003610d005761014435916001600160a01b0383168303610cfc57426024351115610cd0576101243515610ce25760048035600090815260208190526040902001546001600160a01b0316611b0a576040516370a0823160e01b81523360048201526020816024816001600160a01b0388165afa908115611acd578791611ad8575b506101243511610c8c57604051636eb1769f60e11b81523360048201523060248201526020816044816001600160a01b0388165afa908115611acd578791611a9b575b506101243511610c38576111c96101243530336001600160a01b038716612f4f565b6040516111d581612742565b81815285602082015287604082015282606082015233608082015260018060a01b03851660a082015260043560c08201528660e08201526101243561010082015260243561012082015260018060a01b0384166101408201528661016082015286610180820152600435875286602052604087209080518051906001600160401b03821161182f5781906112698554612892565b601f8111611a4d575b50602090601f83116001146119e4578b926119d9575b50508160011b916000199060031b1c19161782555b60208101518051906001600160401b03821161182f5781906112c26001860154612892565b601f8111611988575b50602090601f8311600114611919578b9261190e575b50508160011b916000199060031b1c19161760018301555b60408101518051906001600160401b03821161182f57819061131e6002860154612892565b601f81116118bd575b50602090601f831160011461184e578b92611843575b50508160011b916000199060031b1c19161760028301555b60608101518051906001600160401b03821161182f576113786003850154612892565b601f81116117ea575b50602090601f8311600114611775579180611474959492610180948d9261176a575b50508160011b916000199060031b1c19161760038401555b60808101516004840180546001600160a01b03199081166001600160a01b039384161790915560a0838101516005870180549093169084161790915560c0830151600686015560e0830151600786015561010083015160088601556101208301516009860155610140830151600a9590950180546101608501516001600160a81b03199091169690931695909517911515901b60ff60a01b161783555b0151815460ff60a81b191690151560a81b60ff60a81b16179055565b61147f600435612c4c565b60e43586526002602052600435604087205560405161012081526114da6114cc6114be6114b061012085018a6126af565b8481036020860152856126af565b83810360408501528a6126af565b8281036060840152846126af565b61012435608083015260243560a08301526001600160a01b0361010435811660c084015260e43560e08401528581166101008401528616913391600435917fe00962102cab6d15d8733bbc057ea3d34381c044904c4312bfdf966c2d11589a9181900390a4610104356001600160a01b031661155d575b60206040516004358152f35b610104353b1561175857610104356001600160a01b03163b15610cfc57916115f76115c194926115e58897956115d36040519b8c998a99635e863a5b60e01b8b5260e43560048c015260043560248c015261016060448c01526101648b01906126af565b8981036003190160648b0152906126af565b878103600319016084890152906126af565b8581036003190160a4870152906126af565b913360c485015260018060a01b031660e48401526101243561010484015260243561012484015260018060a01b031661014483015203818360018060a01b0361010435165af19182611741575b5090611734578060033d11611723575b506308c379a0146116e8575b7f7b5bdb2f87e8e20f082bba9be5f7e870728f9bba18540559ccdcdcbb1fc5a0876116a061168c612ec2565b6040519182916020835260208301906126af565b0390a160405162461bcd60e51b815260206004820152601860248201527f494d657373656e676572206e6f74696679206661696c656400000000000000006044820152606490fd5b6116f0612e51565b806116fb5750611660565b60405162461bcd60e51b81526020600482015290819061171f9060248301906126af565b0390fd5b9050600481803e5160e01c38611654565b5038808080808080611551565b6001600160401b03811161097c5760405238611644565b604051633127e9d760e11b8152600490fd5b0151905038806113a3565b90600385018b5260208b20918b5b601f19851681106117d25750926114749594926001926101809583601f198116106117b9575b505050811b0160038401556113bb565b015160001960f88460031b161c191690553880806117a9565b91926020600181928685015181550194019201611783565b600385018b5260208b20601f840160051c810160208510611828575b8c601f840160051c8301821061181e57505050611381565b8155600101611806565b5080611806565b634e487b7160e01b8a52604160045260248afd5b01519050388061133d565b9250600285018b5260208b20908b935b601f19841685106118a2576001945083601f19811610611889575b505050811b016002830155611355565b015160001960f88460031b161c19169055388080611879565b8181015183556020948501946001909301929091019061185e565b909150600285018b5260208b20601f840160051c810160208510611907575b90849392915b8d601f840160051c830182106118fa57505050611327565b81558594506001016118e2565b50806118dc565b0151905038806112e1565b9250600185018b5260208b20908b935b601f198416851061196d576001945083601f19811610611954575b505050811b0160018301556112f9565b015160001960f88460031b161c19169055388080611944565b81810151835560209485019460019093019290910190611929565b909150600185018b5260208b20601f840160051c8101602085106119d2575b90849392915b8d601f840160051c830182106119c5575050506112cb565b81558594506001016119ad565b50806119a7565b015190503880611288565b9250848b5260208b20908b935b601f1984168510611a32576001945083601f19811610611a19575b505050811b01825561129d565b015160001960f88460031b161c19169055388080611a0c565b818101518355602094850194600190930192909101906119f1565b909150848b5260208b20601f840160051c810160208510611a94575b90849392915b8d601f840160051c83018210611a8757505050611272565b8155859450600101611a6f565b5080611a69565b90506020813d602011611ac5575b81611ab660209383612779565b81010312610cf85751386111a7565b3d9150611aa9565b6040513d89823e3d90fd5b90506020813d602011611b02575b81611af360209383612779565b81010312610cf8575138611164565b3d9150611ae6565b60405163748d150960e01b8152600490fd5b50346101b05760203660031901126101b057611b39600435612c72565b6040518091602082528051611ba7611b5f610180928360208701526101a08601906126af565b611b92611b7e602086015192601f1993848983030160408a01526126af565b6040860151838883030160608901526126af565b906060850151908683030160808701526126af565b91608081015160018060a01b0380911660a08601528060a08301511660c086015260c082015160e086015260e082015161010090818701528201518161012091168187015282015190610140911681860152810151906101609115158286015201511515908301520390f35b50346101b05760203660031901126101b05760406020916004358152600283522054604051908152f35b50346101b05760403660031901126101b05760048035600090815260016020526040902001546001600160a01b03161561019e5760043581526001602052600160ff600960408420015460a81c1615151461018c5760043581526001602052600160ff600960408420015460a01c1615151461017a576024356000908152602081905260409020600401546001600160a01b0316611b0a57600435815260016020526040812060018060a01b0360048201541633149081156123f7575b5015610c38576004803582526001602052604080832060098101805460ff60a01b198116600160a01b179091559281015460058201546007830154600684015494519695949390926001600160a01b03928316921690600390611db590611d608a612742565b604051611d7181610e0181856128cc565b8a52604051611d8781610e0181600186016128cc565b60208b0152604051611da081610e0181600286016128cc565b60408b0152610e0160405180948193016128cc565b6060880152608087015260a086015260243560c08601528360e086015261010085015261012084015260018060a01b031661014083015280610160830152806101808301526024358152806020526040812082519283516001600160401b0381116121bb57611e248354612892565b601f81116123b6575b506020601f82116001146123505784958293949592612345575b50508160011b916000199060031b1c19161782555b60208101519283516001600160401b03811161097c57611e7f6001850154612892565b601f8111612301575b506020601f8211600114612295578293949582939261228a575b50508160011b916000199060031b1c19161760018401555b60408201519283516001600160401b038111610a5b57611edd6002830154612892565b601f8111612246575b506020601f82116001146121da57839495829394926121cf575b50508160011b916000199060031b1c19161760028201555b60608301519283516001600160401b0381116121bb57611f3b6003840154612892565b601f8111612177575b506020601f821160011461211b5791816101809261201e9594604098889261176a5750508160011b916000199060031b1c191617600384015560808101516004840180546001600160a01b03199081166001600160a01b039384161790915560a0838101516005870180549093169084161790915560c0830151600686015560e0830151600786015561010083015160088601556101208301516009860155610140830151600a9590950180546101608501516001600160a81b03199091169690931695909517911515901b60ff60a01b16178355611458565b612029602435612c4c565b600435815260016020522060018060a01b0360048201541660018060a01b03600583015416917fe00962102cab6d15d8733bbc057ea3d34381c044904c4312bfdf966c2d11589a600782015491600681015460018060a01b0360088301541660018060a01b03600984015416916120e960405194610120865260036120da6120c96120bb6101208a01600186016128cc565b89810360208b0152846128cc565b88810360408a0152600284016128cc565b918783036060890152016128cc565b95608085015260a084015260c083015260043560e083015261010082015280602435930390a460206040516024358152f35b6003840185526020852095855b601f198416811061215f57508260409761201e96959360019361018096601f198116106117b957505050811b0160038401556113bb565b82820151885560019097019660209283019201612128565b60038401855260208520601f830160051c8101602084106121b4575b601f830160051c820181106121a9575050611f44565b868155600101612193565b5080612193565b634e487b7160e01b84526041600452602484fd5b015190503880611f00565b6002830184526020842090845b601f198416811061222e575060019394959683601f19811610612215575b505050811b016002820155611f18565b015160001960f88460031b161c19169055388080612205565b9091602060018192858b0151815501930191016121e7565b60028301845260208420601f830160051c810160208410612283575b601f830160051c82018110612278575050611ee6565b858155600101612262565b5080612262565b015190503880611ea2565b6001850183526020832090835b601f19841681106122e9575060019394959683601f198116106122d0575b505050811b016001840155611eba565b015160001960f88460031b161c191690553880806122c0565b9091602060018192858b0151815501930191016122a2565b60018501835260208320601f830160051c81016020841061233e575b601f830160051c82018110612333575050611e88565b84815560010161231d565b508061231d565b015190503880611e47565b8385526020852090855b601f198416811061239e575060019394959683601f19811610612385575b505050811b018255611e5c565b015160001960f88460031b161c19169055388080612378565b9091602060018192858b01518155019301910161235a565b83855260208520601f830160051c8101602084106123f0575b601f830160051c820181106123e5575050611e2d565b8681556001016123cf565b50806123cf565b600801546001600160a01b03163314905038611cfa565b50346101b05760209060206003193601126101b05761242b6126d4565b6004546001600160a01b039390929091841681805b8581106124c2575061245190612c06565b9482805b86811061246a5760405180610d6c8a826126ea565b61247381612b5d565b9054600391821b1c83526001875284846004604086200154161461249b575b50600101612455565b81956124bb916124ac600194612b5d565b9054911b1c610dbd828c612c38565b9490612492565b826124cc82612b5d565b9054600391821b1c86526001808852610e016125456040892093610e0161251a604051956124f987612726565b60405161250a81610e01818c6128cc565b8752604051928380928a016128cc565b8b85015260405161253281610e018160028a016128cc565b60408501526040519283809287016128cc565b60608201526101608a6004840154169283608084015260098c6005830154169160a09283860152600681015460c0860152600781015460e08601528d600882015416610100860152015480918d821661012086015260ff9283911c16151561014085015260a81c161515910152146125c0575b600101612440565b906125cc600191612be1565b9190506125b8565b50346101b05760203660031901126101b0576125f1600435612962565b6040518091602082528051612617611b5f6101a0928360208701526101c08601906126af565b91608081015160018060a01b0380911660a08601528060a08301511660c086015260c082015160e086015260e082015161010090818701528201516101209081870152820151610140908187015282015190610160911681860152810151906101809115158286015201511515908301520390f35b60005b83811061269f5750506000910152565b818101518382015260200161268f565b906020916126c88151809281855285808601910161268c565b601f01601f1916010190565b600435906001600160a01b0382168203610c7457565b602090602060408183019282815285518094520193019160005b828110612712575050505090565b835185529381019392810192600101612704565b61018081019081106001600160401b03821117610bfc57604052565b6101a081019081106001600160401b03821117610bfc57604052565b602081019081106001600160401b03821117610bfc57604052565b90601f801991011681019081106001600160401b03821117610bfc57604052565b6001600160401b038111610bfc57601f01601f191660200190565b81601f82011215610c74578035906127cc8261279a565b926127da6040519485612779565b82845260208383010111610c7457816000926020809301838601378301015290565b6001600160401b038111610bfc5760051b60200190565b81601f82011215610c745780359160209161282d846127fc565b9361283b6040519586612779565b808552838086019160051b83010192808411610c7457848301915b8483106128665750505050505090565b82356001600160401b038111610c74578691612887848480948901016127b5565b815201920191612856565b90600182811c921680156128c2575b60208310146128ac57565b634e487b7160e01b600052602260045260246000fd5b91607f16916128a1565b8054600093926128db82612892565b918282526020936001916001811690816000146129435750600114612902575b5050505050565b90939495506000929192528360002092846000945b83861061292f575050505001019038808080806128fb565b805485870183015294019385908201612917565b60ff19168685015250505090151560051b0101915038808080806128fb565b604090815161297081612742565b606091828252826020830152828483015282808301526000908160808401528160a08401528160c08401528160e08401526101009180838501526101209481868601528661014092808488015261016094818689015281610180809901526129f081600052600060205260018060a01b0360046040600020015416151590565b15612ad8578152602081905220875197959660ff96600a9390612a128b612742565b8051612a2281610e0181886128cc565b8b528051612a3781610e0181600189016128cc565b60208c01528051612a4f81610e0181600289016128cc565b818c01525190612a6d82612a6681600388016128cc565b0383612779565b8a015260018060a01b03958660048401541660808b01528660058401541660a08b0152600683015460c08b0152600783015460e08b01526008830154908a0152600982015490890152015492831690860152828260a01c1615159085015260a81c1615159082015290565b50968780968195948294519b612aed8d612742565b8051612af88161275e565b8481528d52805160208e612b0b8361275e565b86835201528051818e612b1d8361275e565b86835201525190612b2d8261275e565b8382528c01528160808c01528160a08c01528160c08c01528160e08c01528a015288015286015284015282015290565b600454811015612b945760046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b0190600090565b634e487b7160e01b600052603260045260246000fd5b600354811015612b945760036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0190600090565b6000198114612bf05760010190565b634e487b7160e01b600052601160045260246000fd5b90612c10826127fc565b612c1d6040519182612779565b8281528092612c2e601f19916127fc565b0190602036910137565b8051821015612b945760209160051b010190565b600354600160401b811015610bfc576104f4816001612c6e9301600355612baa565b9055565b6040908151612c8081612726565b6060808252806020830152808483015280808301526000928360808401528360a08401528360c08401528360e0840152610100918483850152610120908582860152866101409387858801528761016080980152612cf681600052600160205260018060a01b0360046040600020015416151590565b15612dd15790876009939260ff98995260016020522090885198612d198a612726565b8051612d2981610e0181876128cc565b8a528051612d3e81610e0181600188016128cc565b60208b01528051612d5681610e0181600288016128cc565b818b01525190612d6d82612a6681600387016128cc565b89015260018060a01b03948560048301541660808a01528560058301541660a08a0152600682015460c08a0152600782015460e08a01528560088301541690890152015492831690860152828260a01c1615159085015260a81c1615159082015290565b50869485939284925199612de48b612726565b8051612def8161275e565b8481528b528051612dff8161275e565b84815260208c01528051612e128161275e565b848152818c01525190612e248261275e565b8382528a01528160808a01528160a08a01528160c08a01528160e08a015288015286015284015282015290565b600060443d10612eae57604051600319913d83016004833e81516001600160401b03918282113d602484011117612eb157818401948551938411612eb9573d85010160208487010111612eb15750612eae92910160200190612779565b90565b949350505050565b50949350505050565b3d15612eed573d90612ed38261279a565b91612ee16040519384612779565b82523d6000602084013e565b606090565b90808251908181526020809101926020808460051b8301019501936000915b848310612f215750505050505090565b9091929394958480612f3f600193601f198682030187528a516126af565b9801930193019194939290612f11565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815260a08101918183106001600160401b03841117610bfc57612fa792604052612ff4565b565b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448083019390935291815260808101916001600160401b03831182841017610bfc57612fa7926040525b60018060a01b03169061301e600080836020829551910182875af1613017612ec2565b9084613076565b90815191821515928361304e575b5050506130365750565b60249060405190635274afe760e01b82526004820152fd5b819293509060209181010312610d0c5760200151908115918215036101b0575038808061302c565b9061309d575080511561308b57805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806130d0575b6130ae575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156130a656fea264697066735822122065fe76446d5320fa47fe99efc8a0e7b17c882faa829463637a4b537195fe278764736f6c63430008170033