Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 18 from a total of 18 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Teleport | 18378698 | 24 days ago | IN | 0 ETH | 0.000000074678 | ||||
Teleport | 18284756 | 26 days ago | IN | 0 ETH | 0.000000218097 | ||||
Teleport | 18247421 | 27 days ago | IN | 0 ETH | 0.00000250077 | ||||
Teleport | 18246447 | 27 days ago | IN | 0 ETH | 0.000003140526 | ||||
Teleport | 18182947 | 28 days ago | IN | 0 ETH | 0.000004513093 | ||||
Teleport | 18182644 | 29 days ago | IN | 0 ETH | 0.000005055038 | ||||
Teleport | 18095196 | 31 days ago | IN | 0 ETH | 0.000002375783 | ||||
Teleport | 18081992 | 31 days ago | IN | 0 ETH | 0.000010181844 | ||||
Teleport | 18010645 | 32 days ago | IN | 0 ETH | 0.000003047195 | ||||
Teleport | 18010582 | 32 days ago | IN | 0 ETH | 0.000003201147 | ||||
Teleport | 18010473 | 32 days ago | IN | 0 ETH | 0.000002593224 | ||||
Teleport | 17765803 | 38 days ago | IN | 0 ETH | 0.000007718017 | ||||
Teleport | 17381760 | 47 days ago | IN | 0.05 ETH | 0.00002380809 | ||||
Teleport | 17381727 | 47 days ago | IN | 0.05 ETH | 0.000026703933 | ||||
Teleport | 17381663 | 47 days ago | IN | 0.01 ETH | 0.000023670169 | ||||
Teleport | 17381643 | 47 days ago | IN | 0.001 ETH | 0.000024622226 | ||||
Teleport | 17362395 | 47 days ago | IN | 0.000001 ETH | 0.000023115743 | ||||
Init | 17225838 | 51 days ago | IN | 0 ETH | 0.000409164638 |
Latest 2 internal transactions
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
17359702 | 48 days ago | Contract Creation | 0 ETH | |||
17225838 | 51 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
TokenGateway
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// Copyright (C) Polytope Labs Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma solidity 0.8.17; import {DispatchPost} from "@polytope-labs/ismp-solidity/IDispatcher.sol"; import {IIsmpHost} from "@polytope-labs/ismp-solidity/IIsmpHost.sol"; import {Message} from "@polytope-labs/ismp-solidity/Message.sol"; import {StateMachine} from "@polytope-labs/ismp-solidity/StateMachine.sol"; import {BaseIsmpModule, PostRequest, IncomingPostRequest} from "@polytope-labs/ismp-solidity/IIsmpModule.sol"; import {IERC6160Ext20} from "@polytope-labs/erc6160/interfaces/IERC6160Ext20.sol"; import {ERC6160Ext20} from "@polytope-labs/erc6160/tokens/ERC6160Ext20.sol"; import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol"; import {SafeERC20} from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import {Bytes} from "@polytope-labs/solidity-merkle-trees/trie/Bytes.sol"; import {IUniswapV2Router02} from "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol"; import {ICallDispatcher, CallDispatcherParams} from "./CallDispatcher.sol"; struct TeleportParams { // amount to be sent uint256 amount; // Relayer fee uint256 relayerFee; // The token identifier to send bytes32 assetId; // Redeem ERC20 on the destination? bool redeem; // recipient address bytes32 to; // recipient state machine bytes dest; // request timeout in seconds uint64 timeout; // Amount of native token to pay for dispatching the request // if 0 will use the `IIsmpHost.feeToken` uint256 nativeCost; // destination contract call data bytes data; } struct Body { // Amount of the asset to be sent uint256 amount; // The asset identifier bytes32 assetId; // Flag to redeem the erc20 asset on the destination bool redeem; // Sender address bytes32 from; // Recipient address bytes32 to; } struct BodyWithCall { // Amount of the asset to be sent uint256 amount; // The asset identifier bytes32 assetId; // Flag to redeem the erc20 asset on the destination bool redeem; // Sender address bytes32 from; // Recipient address bytes32 to; // Calldata to be passed to the asset destination bytes data; } struct TokenGatewayParamsExt { // Initial params for TokenGateway TokenGatewayParams params; // List of initial assets AssetMetadata[] assets; } struct Asset { // ERC20 token contract address for the asset address erc20; // ERC6160 token contract address for the asset address erc6160; // Asset's identifier bytes32 identifier; } struct ContractInstance { // The state machine identifier for this chain bytes chain; // The token gateway contract address on this chain address moduleId; } enum OnAcceptActions { // Incoming asset from a chain IncomingAsset, // Governance action to update protocol parameters GovernanceAction, // Request from hyperbridge to create a new asset CreateAsset, // Remove an asset from the registry DeregisterAsset, // Change the admin of an asset ChangeAssetAdmin, // Add a new pre-approved address NewContractInstance } struct AssetMetadata { // ERC20 token contract address for the asset address erc20; // ERC6160 token contract address for the asset address erc6160; // Asset's name string name; // Asset's symbol string symbol; // The initial supply of asset uint256 initialSupply; // Initial beneficiary of the total supply address beneficiary; } struct ChangeAssetAdmin { // Address of the asset bytes32 assetId; // The address of the new admin address newAdmin; } struct DeregsiterAsset { // List of assets to deregister bytes32[] assetIds; } // Abi-encoded size of Body struct uint256 constant BODY_BYTES_SIZE = 161; // Params for the TokenGateway contract struct TokenGatewayParams { // address of the IsmpHost contract on this chain address host; // dispatcher for delegating external calls address dispatcher; } /** * @title The TokenGateway. * @author Polytope Labs ([email protected]) * * @notice Allows users send either ERC20 or ERC6160 tokens using Hyperbridge as a message-passing layer. * * @dev ERC20 tokens are custodied in exchange for ERC6160 tokens to be minted on the destination chain, * Otherwise if ERC6160 tokens are sent, then it simply performs a burn-and-mint. */ contract TokenGateway is BaseIsmpModule { using Bytes for bytes; using Message for PostRequest; // TokenGateway protocol parameters TokenGatewayParams private _params; // admin account address private _admin; // mapping of token identifier to erc6160 contracts mapping(bytes32 => address) private _erc6160s; // mapping of token identifier to erc20 contracts mapping(bytes32 => address) private _erc20s; // mapping of keccak256(source chain) to the token gateway contract address mapping(bytes32 => address) private _instances; // User has received some assets event AssetReceived( // The amount that was provided to the user uint256 amount, // The associated request commitment bytes32 commitment, // The source of the funds bytes32 indexed from, // The beneficiary of the funds address indexed beneficiary, // The provided assetId bytes32 indexed assetId ); // User has sent some assets event AssetTeleported( // The beneficiary of the funds bytes32 to, // The destination chain string dest, // The amount that was requested to be sent uint256 amount, // The associated request commitment bytes32 commitment, // The source of the funds address indexed from, // The provided assetId bytes32 indexed assetId, // Flag to redeem funds from the TokenGateway bool redeem ); // User assets could not be delivered and have been refunded. event AssetRefunded( // The amount that was requested to be sent uint256 amount, // The associated request commitment bytes32 commitment, // The beneficiary of the funds address indexed beneficiary, // The provided assetId bytes32 indexed assetId ); // A new asset has been registered event AssetRegistered( // ERC20 token contract address for the asset address erc20, // ERC6160 token contract address for the asset address erc6160, // Asset's name string name, // Asset's symbol string symbol, // Registered asset identifier bytes32 assetId, // The initial supply of asset uint256 initialSupply, // Initial beneficiary of the total supply address beneficiary ); // A new contract instance has been registered event NewContractInstance( // The chain for this new contract instance string chain, // The address for token gateway on this chain address moduleId ); // Contract parameters have been updated by Hyperbridge governance event ParamsUpdated( // The old token gateway params TokenGatewayParams oldParams, // The new token gateway params TokenGatewayParams newParams ); // An asset has been deregistered event AssetRemoved(bytes32 assetId); // An asset owner has requested to change the admin of their asset event AssetAdminChanged( // The ERC6160 token contract address address asset, // The new admin address newAdmin ); // @dev Action is unauthorized error UnauthorizedAction(); // @dev Unexpected zero address error ZeroAddress(); // @dev Provided amount was invalid error InvalidAmount(); // @dev Provided token was unknown error UnknownAsset(); // @dev Protocol invariant violated error InconsistentState(); // @dev Provided address didn't fit address type size error InvalidAddressLength(); // @dev restricts call to the provided `caller` modifier restrict(address caller) { if (msg.sender != caller) revert UnauthorizedAction(); _; } /** * @dev Checks that the request originates from a known instance of the TokenGateway. */ modifier authenticate(PostRequest calldata request) { // TokenGateway only accepts incoming assets from itself bool unknown = !request.from.equals(abi.encodePacked(address(this))) && _instances[keccak256(request.source)] != bytesToAddress(request.from); if (unknown) revert UnauthorizedAction(); _; } constructor(address admin) { _admin = admin; } /** * @dev initialize required parameters */ function init(TokenGatewayParamsExt calldata teleportParams) public restrict(_admin) { _params = teleportParams.params; createAssets(teleportParams.assets); // infinite approval to save on gas SafeERC20.safeIncreaseAllowance( IERC20(IIsmpHost(_params.host).feeToken()), teleportParams.params.host, type(uint256).max ); // admin can only call this once _admin = address(0); } /** * @dev Read the protocol parameters */ function params() external view returns (TokenGatewayParams memory) { return _params; } /** * @dev Fetch the address for an ERC20 asset */ function erc20(bytes32 assetId) public view returns (address) { return _erc20s[assetId]; } /** * @dev Fetch the address for an ERC6160 asset */ function erc6160(bytes32 assetId) public view returns (address) { return _erc6160s[assetId]; } /** * @dev Fetch the TokenGateway instance for a destination. */ function instance(bytes calldata destination) public view returns (address) { address gateway = _instances[keccak256(destination)]; return gateway == address(0) ? address(this) : gateway; } /** * @dev Teleports a local ERC20/ERC6160 asset to the destination chain. Allows users to pay * the Hyperbridge fees in the native token or `IIsmpHost.feeToken` * * @notice If a request times out, users can request a refund permissionlessly through * `HandlerV1.handlePostRequestTimeouts`. */ function teleport(TeleportParams calldata teleportParams) public payable { if (teleportParams.to == bytes32(0)) revert ZeroAddress(); if (teleportParams.amount == 0) revert InvalidAmount(); uint256 msgValue = msg.value; address _erc20 = _erc20s[teleportParams.assetId]; address _erc6160 = _erc6160s[teleportParams.assetId]; address feeToken = IIsmpHost(_params.host).feeToken(); // custody or burn funds to be bridged if (_erc20 != address(0) && !teleportParams.redeem) { address uniswapV2 = IIsmpHost(_params.host).uniswapV2Router(); address WETH = IUniswapV2Router02(uniswapV2).WETH(); if (msgValue >= teleportParams.amount && _erc20 == WETH) { // wrap native token (bool sent, ) = WETH.call{value: teleportParams.amount}(""); if (!sent) revert InconsistentState(); msgValue -= teleportParams.amount; } else { SafeERC20.safeTransferFrom(IERC20(_erc20), msg.sender, address(this), teleportParams.amount); } } else if (_erc6160 != address(0)) { IERC6160Ext20(_erc6160).burn(msg.sender, teleportParams.amount); } else { revert UnknownAsset(); } // dispatch request bytes memory data = teleportParams.data.length > 0 ? abi.encode( BodyWithCall({ from: addressToBytes32(msg.sender), to: teleportParams.to, amount: teleportParams.amount, assetId: teleportParams.assetId, redeem: teleportParams.redeem, data: teleportParams.data }) ) : abi.encode( Body({ from: addressToBytes32(msg.sender), to: teleportParams.to, amount: teleportParams.amount, assetId: teleportParams.assetId, redeem: teleportParams.redeem }) ); data = bytes.concat(hex"00", data); // add enum variant for body DispatchPost memory request = DispatchPost({ dest: teleportParams.dest, to: abi.encodePacked(instance(teleportParams.dest)), body: data, timeout: teleportParams.timeout, fee: teleportParams.relayerFee, payer: msg.sender }); bytes32 commitment = bytes32(0); if (msgValue >= teleportParams.nativeCost && teleportParams.nativeCost > 0) { // there's some native tokens left to pay for request dispatch commitment = IIsmpHost(_params.host).dispatch{value: teleportParams.nativeCost}(request); } else { // try to pay for dispatch with fee token uint256 fee = (IIsmpHost(_params.host).perByteFee() * data.length) + teleportParams.relayerFee; SafeERC20.safeTransferFrom(IERC20(feeToken), msg.sender, address(this), fee); commitment = IIsmpHost(_params.host).dispatch(request); } emit AssetTeleported({ from: msg.sender, to: teleportParams.to, dest: string(teleportParams.dest), assetId: teleportParams.assetId, amount: teleportParams.amount, redeem: teleportParams.redeem, commitment: commitment }); } /** * @dev Entry point for all cross-chain messages. */ function onAccept(IncomingPostRequest calldata incoming) external override restrict(_params.host) { OnAcceptActions action = OnAcceptActions(uint8(incoming.request.body[0])); if (action == OnAcceptActions.IncomingAsset) { if (incoming.request.body.length > BODY_BYTES_SIZE) { handleIncomingAssetWithCall(incoming); } else { handleIncomingAssetWithoutCall(incoming); } } else if (action == OnAcceptActions.GovernanceAction) { handleGovernance(incoming.request); } else if (action == OnAcceptActions.CreateAsset) { handleCreateAsset(incoming.request); } else if (action == OnAcceptActions.DeregisterAsset) { handleDeregisterAssets(incoming.request); } else if (action == OnAcceptActions.ChangeAssetAdmin) { handleChangeAssetAdmin(incoming.request); } else if (action == OnAcceptActions.NewContractInstance) { handleNewContractInstance(incoming.request); } } /** * @dev Triggered when a previously sent out request is confirmed to be timed-out by the IsmpHost. * @notice This means the funds could not be sent, we simply refund the user's assets here. */ function onPostRequestTimeout(PostRequest calldata request) external override restrict(_params.host) { Body memory body; if (request.body.length > BODY_BYTES_SIZE) { BodyWithCall memory bodyWithCall = abi.decode(request.body[1:], (BodyWithCall)); body = Body({ amount: bodyWithCall.amount, assetId: bodyWithCall.assetId, redeem: bodyWithCall.redeem, from: bodyWithCall.from, to: bodyWithCall.to }); } else { body = abi.decode(request.body[1:], (Body)); } address _erc20 = _erc20s[body.assetId]; address _erc6160 = _erc6160s[body.assetId]; address from = bytes32ToAddress(body.from); if (_erc20 != address(0) && !body.redeem) { SafeERC20.safeTransfer(IERC20(_erc20), from, body.amount); } else if (_erc6160 != address(0)) { IERC6160Ext20(_erc6160).mint(from, body.amount); } else { revert InconsistentState(); } emit AssetRefunded({commitment: request.hash(), beneficiary: from, amount: body.amount, assetId: body.assetId}); } /** * @dev Execute an incoming request with no calldata */ function handleIncomingAssetWithoutCall( IncomingPostRequest calldata incoming ) internal authenticate(incoming.request) { Body memory body = abi.decode(incoming.request.body[1:], (Body)); bytes32 commitment = incoming.request.hash(); handleIncomingAsset(body); emit AssetReceived({ commitment: commitment, beneficiary: bytes32ToAddress(body.to), from: body.from, amount: body.amount, assetId: body.assetId }); } /** * @dev Execute an incoming request with calldata, delegates calls to 3rd party contracts to * the `_params.dispatcher` for safety reasons. */ function handleIncomingAssetWithCall( IncomingPostRequest calldata incoming ) internal authenticate(incoming.request) { BodyWithCall memory body = abi.decode(incoming.request.body[1:], (BodyWithCall)); bytes32 commitment = incoming.request.hash(); handleIncomingAsset( Body({ amount: body.amount, assetId: body.assetId, redeem: body.redeem, from: body.from, to: body.to }) ); ICallDispatcher(_params.dispatcher).dispatch(body.data); emit AssetReceived({ commitment: commitment, beneficiary: bytes32ToAddress(body.to), from: body.from, amount: body.amount, assetId: body.assetId }); } /** * @dev Executes the asset disbursement for the provided request */ function handleIncomingAsset(Body memory body) internal { address _erc20 = _erc20s[body.assetId]; address _erc6160 = _erc6160s[body.assetId]; if (_erc20 != address(0) && body.redeem) { // a relayer/user is redeeming the native asset SafeERC20.safeTransfer(IERC20(_erc20), bytes32ToAddress(body.to), body.amount); } else if (_erc6160 != address(0)) { IERC6160Ext20(_erc6160).mint(bytes32ToAddress(body.to), body.amount); } else { revert UnknownAsset(); } } /** * @dev Handles requests from cross-chain governance */ function handleGovernance(PostRequest calldata request) internal { if (!request.source.equals(IIsmpHost(_params.host).hyperbridge())) revert UnauthorizedAction(); TokenGatewayParams memory newParams = abi.decode(request.body[1:], (TokenGatewayParams)); emit ParamsUpdated({oldParams: _params, newParams: newParams}); _params = newParams; } /** * @dev registers a new asset as requested by cross-chain governance */ function handleCreateAsset(PostRequest calldata request) internal { if (!request.source.equals(IIsmpHost(_params.host).hyperbridge())) revert UnauthorizedAction(); AssetMetadata[] memory assets = new AssetMetadata[](1); assets[0] = abi.decode(request.body[1:], (AssetMetadata)); createAssets(assets); } /** * @dev Deregisters the asset from TokenGateway. Users will be unable to bridge the asset * through TokenGateway once they are deregistered */ function handleDeregisterAssets(PostRequest calldata request) internal { if (!request.source.equals(IIsmpHost(_params.host).hyperbridge())) revert UnauthorizedAction(); DeregsiterAsset memory deregister = abi.decode(request.body[1:], (DeregsiterAsset)); uint256 length = deregister.assetIds.length; for (uint256 i = 0; i < length; ++i) { delete _erc20s[deregister.assetIds[i]]; delete _erc6160s[deregister.assetIds[i]]; emit AssetRemoved({assetId: deregister.assetIds[i]}); } } /** * @dev Changes the asset admin from this contract to some other address. Changing the admin to a * zero address is disallowed for safety reasons */ function handleChangeAssetAdmin(PostRequest calldata request) internal { if (!request.source.equals(IIsmpHost(_params.host).hyperbridge())) revert UnauthorizedAction(); ChangeAssetAdmin memory asset = abi.decode(request.body[1:], (ChangeAssetAdmin)); address erc6160Address = _erc6160s[asset.assetId]; if (asset.newAdmin == address(0)) revert ZeroAddress(); if (erc6160Address == address(0)) revert UnknownAsset(); IERC6160Ext20(erc6160Address).changeAdmin(asset.newAdmin); emit AssetAdminChanged({asset: erc6160Address, newAdmin: asset.newAdmin}); } /** * @dev registers a new instance of `TokenGateway` to permit receiving assets */ function handleNewContractInstance(PostRequest calldata request) internal { if (!request.source.equals(IIsmpHost(_params.host).hyperbridge())) revert UnauthorizedAction(); ContractInstance memory newInstance = abi.decode(request.body[1:], (ContractInstance)); _instances[keccak256(newInstance.chain)] = newInstance.moduleId; emit NewContractInstance({chain: string(newInstance.chain), moduleId: newInstance.moduleId}); } /** * @dev Creates a new entry for the provided asset in the mappings. If there's no existing * ERC6160 address provided, then a contract for the asset is created. */ function createAssets(AssetMetadata[] memory assets) internal { uint256 length = assets.length; for (uint256 i = 0; i < length; ++i) { AssetMetadata memory asset = assets[i]; bytes32 identifier = keccak256(bytes(asset.symbol)); string memory symbol = asset.symbol; if (asset.erc20 != address(0)) { symbol = string.concat(symbol, ".h"); } if (asset.erc6160 == address(0)) { ERC6160Ext20 erc6160Asset = new ERC6160Ext20{salt: identifier}(address(this), asset.name, symbol); asset.erc6160 = address(erc6160Asset); if (asset.beneficiary != address(0) && asset.initialSupply != 0) { erc6160Asset.mint(asset.beneficiary, asset.initialSupply); } } _erc20s[identifier] = asset.erc20; _erc6160s[identifier] = asset.erc6160; emit AssetRegistered({ erc20: asset.erc20, erc6160: asset.erc6160, name: asset.name, symbol: asset.symbol, assetId: identifier, beneficiary: asset.beneficiary, initialSupply: asset.initialSupply }); } } /** * @dev Converts bytes to address. * @param _bytes bytes value to be converted * @return addr returns the address */ function bytesToAddress(bytes memory _bytes) internal pure returns (address addr) { if (_bytes.length != 20) { revert InvalidAddressLength(); } assembly { addr := mload(add(_bytes, 20)) } } function addressToBytes32(address _address) internal pure returns (bytes32) { return bytes32(uint256(uint160(_address))); } function bytes32ToAddress(bytes32 _bytes) internal pure returns (address) { return address(uint160(uint256(_bytes))); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {StateMachineHeight} from "./IConsensusClient.sol"; import {PostRequest} from "./Message.sol"; // @notice An object for dispatching post requests to the Hyperbridge struct DispatchPost { // bytes representation of the destination state machine bytes dest; // the destination module bytes to; // the request body bytes body; // timeout for this request in seconds uint64 timeout; // the amount put up to be paid to the relayer, // this is charged in `IIsmpHost.feeToken` to `msg.sender` uint256 fee; // who pays for this request? address payer; } // @notice An object for dispatching get requests to the Hyperbridge struct DispatchGet { // bytes representation of the destination state machine bytes dest; // height at which to read the state machine uint64 height; // storage keys to read bytes[] keys; // timeout for this request in seconds uint64 timeout; // Hyperbridge protocol fees for processing this request. uint256 fee; // Some application-specific metadata relating to this request bytes context; } struct DispatchPostResponse { // The request that initiated this response PostRequest request; // bytes for post response bytes response; // timeout for this response in seconds uint64 timeout; // the amount put up to be paid to the relayer, // this is charged in `IIsmpHost.feeToken` to `msg.sender` uint256 fee; // who pays for this request? address payer; } /* * @title The Ismp Dispatcher * @author Polytope Labs ([email protected]) * * @notice The IHandler interface serves as the entry point for ISMP datagrams, i.e consensus, requests & response messages. */ interface IDispatcher { /** * @dev Dispatch a POST request to Hyperbridge * * @notice Payment for the request can be made with either the native token or the IIsmpHost.feeToken. * If native tokens are supplied, it will perform a swap under the hood using the local uniswap router. * Will revert if enough native tokens are not provided. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * @param request - post request * @return commitment - the request commitment */ function dispatch(DispatchPost memory request) external payable returns (bytes32 commitment); /** * @dev Dispatch a GET request to Hyperbridge * * @notice Payment for the request can be made with either the native token or the IIsmpHost.feeToken. * If native tokens are supplied, it will perform a swap under the hood using the local uniswap router. * Will revert if enough native tokens are not provided. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * @param request - get request * @return commitment - the request commitment */ function dispatch(DispatchGet memory request) external payable returns (bytes32 commitment); /** * @dev Dispatch a POST response to Hyperbridge * * @notice Payment for the request can be made with either the native token or the IIsmpHost.feeToken. * If native tokens are supplied, it will perform a swap under the hood using the local uniswap router. * Will revert if enough native tokens are not provided. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * @param response - post response * @return commitment - the request commitment */ function dispatch(DispatchPostResponse memory response) external payable returns (bytes32 commitment); /** * @dev Increase the relayer fee for a previously dispatched request. * This is provided for use only on pending requests, such that when they timeout, * the user can recover the entire relayer fee. * * @notice Payment can be made with either the native token or the IIsmpHost.feeToken. * If native tokens are supplied, it will perform a swap under the hood using the local uniswap router. * Will revert if enough native tokens are not provided. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * If called on an already delivered request, these funds will be seen as a donation to the hyperbridge protocol. * @param commitment - The request commitment * @param amount - The amount provided in `IIsmpHost.feeToken()` */ function fundRequest(bytes32 commitment, uint256 amount) external payable; /** * @dev Increase the relayer fee for a previously dispatched response. * This is provided for use only on pending responses, such that when they timeout, * the user can recover the entire relayer fee. * * @notice Payment can be made with either the native token or the IIsmpHost.feeToken. * If native tokens are supplied, it will perform a swap under the hood using the local uniswap router. * Will revert if enough native tokens are not provided. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * If called on an already delivered response, these funds will be seen as a donation to the hyperbridge protocol. * @param commitment - The response commitment * @param amount - The amount to be provided in `IIsmpHost.feeToken()` */ function fundResponse(bytes32 commitment, uint256 amount) external payable; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {StateCommitment, StateMachineHeight} from "./IConsensusClient.sol"; import {IDispatcher} from "./IDispatcher.sol"; import {PostRequest, PostResponse, GetResponse, GetRequest} from "./Message.sol"; // Some metadata about the request fee struct FeeMetadata { // the relayer fee uint256 fee; // user who initiated the request address sender; } struct ResponseReceipt { // commitment of the response object bytes32 responseCommitment; // address of the relayer responsible for this response delivery address relayer; } // Various frozen states of the IIsmpHost enum FrozenStatus { // Host is operating normally None, // Host is currently disallowing incoming datagrams Incoming, // Host is currently disallowing outgoing messages Outgoing, // All actions have been frozen All } /** * @title The Ismp Host Interface * @author Polytope Labs ([email protected]) * * @notice The Ismp Host interface sits at the core of the interoperable state machine protocol, * It which encapsulates the interfaces required for ISMP datagram handlers and modules. * * @dev The IsmpHost provides the necessary storage interface for the ISMP handlers to process * ISMP messages, the IsmpDispatcher provides the interfaces applications use for dispatching requests * and responses. This host implementation delegates all verification logic to the IHandler contract. * It is only responsible for dispatching incoming & outgoing messages as well as managing * the state of the ISMP protocol. */ interface IIsmpHost is IDispatcher { /** * @return the host admin */ function admin() external returns (address); /** * @return the address of the fee token ERC-20 contract on this state machine */ function feeToken() external view returns (address); /** * @return the per-byte fee for outgoing messages. */ function perByteFee() external view returns (uint256); /** * @return the host state machine id */ function host() external view returns (bytes memory); /** * @return the state machine identifier for the connected hyperbridge instance */ function hyperbridge() external view returns (bytes memory); /** * @return the host timestamp */ function timestamp() external view returns (uint256); /** * @dev Returns the nonce immediately available for requests * @return the `nonce` */ function nonce() external view returns (uint256); /** * @dev Returns the fisherman responsible for vetoing the given state machine height. * @return the `fisherman` address */ function vetoes(uint256 paraId, uint256 height) external view returns (address); /** * @return the `frozen` status */ function frozen() external view returns (FrozenStatus); /** * @dev Returns the address for the Uniswap V2 Router implementation used for swaps * @return routerAddress - The address to the in-use RouterV02 implementation */ function uniswapV2Router() external view returns (address); /** * @dev Returns the fee required for 3rd party applications to access hyperbridge state commitments. * @return the `stateCommitmentFee` */ function stateCommitmentFee() external view returns (uint256); /** * @notice Charges the stateCommitmentFee to 3rd party applications. * If native tokens are provided, will attempt to swap them for the stateCommitmentFee. * If not enough native tokens are supplied, will revert. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * @param height - state machine height * @return the state commitment at `height` */ function stateMachineCommitment(StateMachineHeight memory height) external payable returns (StateCommitment memory); /** * @param height - state machine height * @return the state machine commitment update time at `height` */ function stateMachineCommitmentUpdateTime(StateMachineHeight memory height) external returns (uint256); /** * @return the consensus client contract */ function consensusClient() external view returns (address); /** * @return the last updated time of the consensus client */ function consensusUpdateTime() external view returns (uint256); /** * @return the latest state machine height for the given stateMachineId. If it returns 0, the state machine is unsupported. */ function latestStateMachineHeight(uint256 stateMachineId) external view returns (uint256); /** * @return the state of the consensus client */ function consensusState() external view returns (bytes memory); /** * @dev Check the response status for a given request. * @return `response` status */ function responded(bytes32 commitment) external view returns (bool); /** * @param commitment - commitment to the request * @return relayer address */ function requestReceipts(bytes32 commitment) external view returns (address); /** * @param commitment - commitment to the request of the response * @return response receipt */ function responseReceipts(bytes32 commitment) external view returns (ResponseReceipt memory); /** * @param commitment - commitment to the request * @return existence status of an outgoing request commitment */ function requestCommitments(bytes32 commitment) external view returns (FeeMetadata memory); /** * @param commitment - commitment to the response * @return existence status of an outgoing response commitment */ function responseCommitments(bytes32 commitment) external view returns (FeeMetadata memory); /** * @return the challenge period */ function challengePeriod() external view returns (uint256); /** * @return the unstaking period */ function unStakingPeriod() external view returns (uint256); /** * @dev set the new frozen state of the host, only the admin or handler can call this. * @param newState - the new frozen state */ function setFrozenState(FrozenStatus newState) external; /** * @dev Store an encoded consensus state * @param state new consensus state */ function storeConsensusState(bytes memory state) external; /** * @dev Store the commitment at `state height` * @param height state machine height * @param commitment state commitment */ function storeStateMachineCommitment(StateMachineHeight memory height, StateCommitment memory commitment) external; /** * @dev Delete the state commitment at given state height. */ function deleteStateMachineCommitment(StateMachineHeight memory height, address fisherman) external; /** * @dev Dispatch an incoming request to destination module * @param request - post request */ function dispatchIncoming(PostRequest memory request, address relayer) external; /** * @dev Dispatch an incoming post response to source module * @param response - post response */ function dispatchIncoming(PostResponse memory response, address relayer) external; /** * @dev Dispatch an incoming get response to source module * @param response - get response */ function dispatchIncoming(GetResponse memory response, address relayer) external; /** * @dev Dispatch an incoming get timeout to source module * @param timeout - timed-out get request */ function dispatchTimeOut(GetRequest memory timeout, FeeMetadata memory meta, bytes32 commitment) external; /** * @dev Dispatch an incoming post timeout to source module * @param timeout - timed-out post request */ function dispatchTimeOut(PostRequest memory timeout, FeeMetadata memory meta, bytes32 commitment) external; /** * @dev Dispatch an incoming post response timeout to source module * @param timeout - timed-out post response */ function dispatchTimeOut(PostResponse memory timeout, FeeMetadata memory meta, bytes32 commitment) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {StateMachineHeight} from "./IConsensusClient.sol"; import {StorageValue} from "@polytope-labs/solidity-merkle-trees/Types.sol"; struct PostRequest { // the source state machine of this request bytes source; // the destination state machine of this request bytes dest; // request nonce uint64 nonce; // Module Id of this request origin bytes from; // destination module id bytes to; // timestamp by which this request times out. uint64 timeoutTimestamp; // request body bytes body; } struct GetRequest { // the source state machine of this request bytes source; // the destination state machine of this request bytes dest; // request nonce uint64 nonce; // Module Id of this request origin address from; // timestamp by which this request times out. uint64 timeoutTimestamp; // Storage keys to read. bytes[] keys; // height at which to read destination state machine uint64 height; // Some application-specific metadata relating to this request bytes context; } struct GetResponse { // The request that initiated this response GetRequest request; // storage values for get response StorageValue[] values; } struct PostResponse { // The request that initiated this response PostRequest request; // bytes for post response bytes response; // timestamp by which this response times out. uint64 timeoutTimestamp; } // A post request as a leaf in a merkle tree struct PostRequestLeaf { // The request PostRequest request; // It's index in the mmr leaves uint256 index; // it's k-index uint256 kIndex; } // A post response as a leaf in a merkle tree struct PostResponseLeaf { // The response PostResponse response; // It's index in the mmr leaves uint256 index; // it's k-index uint256 kIndex; } // A get response as a leaf in a merkle mountain range tree struct GetResponseLeaf { // The response GetResponse response; // It's index in the mmr leaves uint256 index; // it's k-index uint256 kIndex; } // A merkle mountain range proof. struct Proof { // height of the state machine StateMachineHeight height; // the multi-proof bytes32[] multiproof; // The total number of leaves in the mmr for this proof. uint256 leafCount; } // A message for handling incoming requests struct PostRequestMessage { // proof for the requests Proof proof; // The requests, contained in the merkle mountain range tree PostRequestLeaf[] requests; } // A message for handling incoming GET responses struct GetResponseMessage { // proof for the responses Proof proof; // The responses, contained in the merkle mountain range tree GetResponseLeaf[] responses; } struct GetTimeoutMessage { // requests which have timed-out GetRequest[] timeouts; // the height of the state machine proof StateMachineHeight height; // non-membership proof of the requests bytes[] proof; } struct PostRequestTimeoutMessage { // requests which have timed-out PostRequest[] timeouts; // the height of the state machine proof StateMachineHeight height; // non-membership proof of the requests bytes[] proof; } struct PostResponseTimeoutMessage { // responses which have timed-out PostResponse[] timeouts; // the height of the state machine proof StateMachineHeight height; // non-membership proof of the requests bytes[] proof; } // A message for handling incoming responses struct PostResponseMessage { // proof for the responses Proof proof; // the responses, contained in a merkle tree leaf PostResponseLeaf[] responses; } library Message { /** * @dev Calculates the absolute timeout value for a PostRequest */ function timeout(PostRequest memory req) internal pure returns (uint64) { if (req.timeoutTimestamp == 0) { return type(uint64).max; } else { return req.timeoutTimestamp; } } /** * @dev Calculates the absolute timeout value for a GetRequest */ function timeout(GetRequest memory req) internal pure returns (uint64) { if (req.timeoutTimestamp == 0) { return type(uint64).max; } else { return req.timeoutTimestamp; } } /** * @dev Calculates the absolute timeout value for a PostResponse */ function timeout(PostResponse memory res) internal pure returns (uint64) { if (res.timeoutTimestamp == 0) { return type(uint64).max; } else { return res.timeoutTimestamp; } } /** * @dev Encode the given post request for commitment */ function encode(PostRequest memory req) internal pure returns (bytes memory) { return abi.encodePacked(req.source, req.dest, req.nonce, req.timeoutTimestamp, req.from, req.to, req.body); } /** * @dev Encode the given get request for commitment */ function encode(GetRequest memory req) internal pure returns (bytes memory) { bytes memory keysEncoding = bytes(""); uint256 len = req.keys.length; for (uint256 i = 0; i < len; i++) { keysEncoding = bytes.concat(keysEncoding, req.keys[i]); } return abi.encodePacked( req.source, req.dest, req.nonce, req.height, req.timeoutTimestamp, abi.encodePacked(req.from), keysEncoding, req.context ); } /** * @dev Returns the commitment for the given post response */ function hash(PostResponse memory res) internal pure returns (bytes32) { return keccak256(bytes.concat(encode(res.request), abi.encodePacked(res.response, res.timeoutTimestamp))); } /** * @dev Returns the commitment for the given post request */ function hash(PostRequest memory req) internal pure returns (bytes32) { return keccak256(encode(req)); } /** * @dev Returns the commitment for the given get request */ function hash(GetRequest memory req) internal pure returns (bytes32) { return keccak256(encode(req)); } /** * @dev Returns the commitment for the given get response */ function hash(GetResponse memory res) internal pure returns (bytes32) { bytes memory response = bytes(""); uint256 len = res.values.length; for (uint256 i = 0; i < len; i++) { response = bytes.concat(response, bytes.concat(res.values[i].key, res.values[i].value)); } return keccak256(bytes.concat(encode(res.request), response)); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {Strings} from "openzeppelin/utils/Strings.sol"; library StateMachine { /// @notice The identifier for the relay chain. uint256 public constant RELAY_CHAIN = 0; // @notice Address a state machine on the polkadot relay chain function polkadot(uint256 id) internal pure returns (bytes memory) { return bytes(string.concat("POLKADOT-", Strings.toString(id))); } // @notice Address a state machine on the kusama relay chain function kusama(uint256 id) internal pure returns (bytes memory) { return bytes(string.concat("KUSAMA-", Strings.toString(id))); } // @notice Address an evm state machine function evm(uint chainid) internal pure returns (bytes memory) { return bytes(string.concat("EVM-", Strings.toString(chainid))); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {PostRequest, PostResponse, GetResponse, GetRequest} from "./Message.sol"; import {DispatchPost, DispatchPostResponse} from "./IDispatcher.sol"; import {IIsmpHost} from "./IIsmpHost.sol"; struct IncomingPostRequest { // The Post request PostRequest request; // Relayer responsible for delivering the request address relayer; } struct IncomingPostResponse { // The Post response PostResponse response; // Relayer responsible for delivering the response address relayer; } struct IncomingGetResponse { // The Get response GetResponse response; // Relayer responsible for delivering the response address relayer; } interface IIsmpModule { /** * @dev Called by the `IsmpHost` to notify a module of a new request the module may choose to respond immediately, or in a later block * @param incoming post request */ function onAccept(IncomingPostRequest memory incoming) external; /** * @dev Called by the `IsmpHost` to notify a module of a post response to a previously sent out request * @param incoming post response */ function onPostResponse(IncomingPostResponse memory incoming) external; /** * @dev Called by the `IsmpHost` to notify a module of a get response to a previously sent out request * @param incoming get response */ function onGetResponse(IncomingGetResponse memory incoming) external; /** * @dev Called by the `IsmpHost` to notify a module of post requests that were previously sent but have now timed-out * @param request post request */ function onPostRequestTimeout(PostRequest memory request) external; /** * @dev Called by the `IsmpHost` to notify a module of post requests that were previously sent but have now timed-out * @param request post request */ function onPostResponseTimeout(PostResponse memory request) external; /** * @dev Called by the `IsmpHost` to notify a module of get requests that were previously sent but have now timed-out * @param request get request */ function onGetTimeout(GetRequest memory request) external; } // @notice Abstract contract to make implementing `IIsmpModule` easier. abstract contract BaseIsmpModule is IIsmpModule { // @notice Chain is not supported error UnsupportedChain(); // @notice Call was not expected error UnexpectedCall(); // @notice Account is unauthorized error UnauthorizedAccount(); // @dev restricts caller to the local `IsmpHost` modifier onlyHost() { if (msg.sender != hostAddr()) revert UnauthorizedAccount(); _; } // @dev Returns the `IsmpHost` address for the current chain. // The `IsmpHost` is an immutable contract that will never change. function hostAddr() internal view returns (address h) { assembly { switch chainid() // Ethereum Sepolia case 11155111 { h := 0xF1c7a386325B7D22025D7542b28Ee881Cdf107b3 } // Arbitrum Sepolia case 421614 { h := 0x286e1FE1c323EE626bE802b13a5184b588eD14Cb } // Optimism Sepolia case 11155420 { h := 0x625c531a56DB772CC36313d0A0114956aD8b56c2 } // Base Sepolia case 84532 { h := 0xae9f490EE05588fDD857A078cFC1f5f30ae7185f } // Binance Smart Chain Testnet case 97 { h := 0xeB8977EDCdA5FaBDcDdEB39861Df25E8821a9e9b } } if (h == address(0)) revert UnsupportedChain(); } // @dev returns the quoted fee for a dispatch function quoteFee(DispatchPost memory post) internal view returns (uint256) { return post.body.length * IIsmpHost(hostAddr()).perByteFee(); } // @dev returns the quoted fee for a dispatch function quoteFee(DispatchPostResponse memory res) internal view returns (uint256) { return res.response.length * IIsmpHost(hostAddr()).perByteFee(); } function onAccept(IncomingPostRequest calldata) external virtual onlyHost { revert UnexpectedCall(); } function onPostRequestTimeout(PostRequest memory) external virtual onlyHost { revert UnexpectedCall(); } function onPostResponse(IncomingPostResponse memory) external virtual onlyHost { revert UnexpectedCall(); } function onPostResponseTimeout(PostResponse memory) external virtual onlyHost { revert UnexpectedCall(); } function onGetResponse(IncomingGetResponse memory) external virtual onlyHost { revert UnexpectedCall(); } function onGetTimeout(GetRequest memory) external virtual onlyHost { revert UnexpectedCall(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {IERC_ACL_CORE} from "./IERCAclCore.sol"; // The EIP-165 identifier of this interface is 0xd0017968 interface IERC5679Ext20 { function mint(address _to, uint256 _amount) external; function burn(address _from, uint256 _amount) external; } /** * @dev Interface of the ERC6160 standard, as defined in * https://github.com/polytope-labs/EIPs/blob/master/EIPS/eip-6160.md. * * @author Polytope Labs * * The EIP-165 identifier of this interface is 0xbbb8b47e */ interface IERC6160Ext20 is IERC5679Ext20, IERC_ACL_CORE {}
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "openzeppelin/token/ERC20/ERC20.sol"; import "openzeppelin/utils/introspection/ERC165Storage.sol"; import {IERC6160Ext20, IERC5679Ext20, IERC_ACL_CORE} from "../interfaces/IERC6160Ext20.sol"; /// @notice Thrown if account is not the admin of a given role error NotRoleAdmin(); /// @notice Thrown if account does not have required permission error PermissionDenied(); contract ERC6160Ext20 is ERC165Storage, ERC20, IERC6160Ext20 { /// @notice InterfaceId for ERC6160Ext20 bytes4 private constant IERC6160Ext20_ID = 0xb6ba5da3; /// @notice The Id of Role required to mint token bytes32 public constant MINTER_ROLE = keccak256("MINTER ROLE"); /// @notice The Id of Role required to burn token bytes32 public constant BURNER_ROLE = keccak256("BURNER ROLE"); /// @notice mapping of defined roles in the contract mapping(bytes32 => mapping(address => bool)) internal _roles; /// @notice mapping of admins of defined roles mapping(bytes32 => mapping(address => bool)) internal _rolesAdmin; constructor(address admin, string memory name, string memory symbol) ERC20(name, symbol) { _registerInterface(IERC6160Ext20_ID); _registerInterface(type(IERC5679Ext20).interfaceId); _registerInterface(type(IERC_ACL_CORE).interfaceId); _rolesAdmin[MINTER_ROLE][admin] = true; _rolesAdmin[BURNER_ROLE][admin] = true; _roles[MINTER_ROLE][admin] = true; _roles[BURNER_ROLE][admin] = true; } /// @notice Mints token to the specified account `_to` function mint(address _to, uint256 _amount) public { if (!_isRoleAdmin(MINTER_ROLE) && !hasRole(MINTER_ROLE, _msgSender())) revert PermissionDenied(); super._mint(_to, _amount); } /// @notice Burns token associated with the specified account `_from` function burn(address _from, uint256 _amount) public { if (!_isRoleAdmin(BURNER_ROLE) && !hasRole(BURNER_ROLE, _msgSender())) revert PermissionDenied(); super._burn(_from, _amount); } /// @notice Grants a given role to the specified account /// @dev This method can only be called from an admin of the given role /// @param _role The role to set for the account /// @param _account The account to be granted the specified role function grantRole(bytes32 _role, address _account) public { if (!_isRoleAdmin(_role)) revert NotRoleAdmin(); _roles[_role][_account] = true; } /// @notice Revokes a given role to the specified account /// @dev This method can only be called from an admin of the given role /// @param _role The role to revoke for the account /// @param _account The account whose role is to be revoked function revokeRole(bytes32 _role, address _account) public { if (!_isRoleAdmin(_role)) revert NotRoleAdmin(); _roles[_role][_account] = false; } /// @notice Changes the admin account to the provided address /// @dev This method can only be called from an admin of the given role /// @param newAdmin Address of the new admin function changeAdmin(address newAdmin) public { if (!_isRoleAdmin(MINTER_ROLE) || !_isRoleAdmin(BURNER_ROLE)) revert NotRoleAdmin(); delete _rolesAdmin[MINTER_ROLE][_msgSender()]; delete _rolesAdmin[BURNER_ROLE][_msgSender()]; if (newAdmin == address(0)) { return; } _rolesAdmin[MINTER_ROLE][newAdmin] = true; _rolesAdmin[BURNER_ROLE][newAdmin] = true; } /// @notice EIP-165 style to query for supported interfaces /// @param _interfaceId The interface-id to query for support function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC165Storage) returns (bool) { return super.supportsInterface(_interfaceId); } /// @notice Checks that an account has a specified role /// @param _role The role to query /// @param _account The account to query for the given role function hasRole(bytes32 _role, address _account) public view returns (bool) { return _roles[_role][_account]; } /// @notice Get the Minter-Role ID function getMinterRole() public pure returns (bytes32) { return MINTER_ROLE; } /// @notice Get the Burner-Role ID function getBurnerRole() public pure returns (bytes32) { return BURNER_ROLE; } /** * INTERNAL FUNCTIONS * */ function _isRoleAdmin(bytes32 role) internal view returns (bool) { return _rolesAdmin[role][_msgSender()]; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 import {Memory} from "./Memory.sol"; struct ByteSlice { bytes data; uint256 offset; } library Bytes { uint256 internal constant BYTES_HEADER_SIZE = 32; // Checks if two `bytes memory` variables are equal. This is done using hashing, // which is much more gas efficient then comparing each byte individually. // Equality means that: // - 'self.length == other.length' // - For 'n' in '[0, self.length)', 'self[n] == other[n]' function equals(bytes memory self, bytes memory other) internal pure returns (bool equal) { if (self.length != other.length) { return false; } uint256 addr; uint256 addr2; assembly { addr := add(self, /*BYTES_HEADER_SIZE*/ 32) addr2 := add(other, /*BYTES_HEADER_SIZE*/ 32) } equal = Memory.equals(addr, addr2, self.length); } function readByte(ByteSlice memory self) internal pure returns (uint8) { if (self.offset + 1 > self.data.length) { revert("Out of range"); } uint8 b = uint8(self.data[self.offset]); self.offset += 1; return b; } // Copies 'len' bytes from 'self' into a new array, starting at the provided 'startIndex'. // Returns the new copy. // Requires that: // - 'startIndex + len <= self.length' // The length of the substring is: 'len' function read(ByteSlice memory self, uint256 len) internal pure returns (bytes memory) { require(self.offset + len <= self.data.length); if (len == 0) { return ""; } uint256 addr = Memory.dataPtr(self.data); bytes memory slice = Memory.toBytes(addr + self.offset, len); self.offset += len; return slice; } // Copies a section of 'self' into a new array, starting at the provided 'startIndex'. // Returns the new copy. // Requires that 'startIndex <= self.length' // The length of the substring is: 'self.length - startIndex' function substr(bytes memory self, uint256 startIndex) internal pure returns (bytes memory) { require(startIndex <= self.length); uint256 len = self.length - startIndex; uint256 addr = Memory.dataPtr(self); return Memory.toBytes(addr + startIndex, len); } // Copies 'len' bytes from 'self' into a new array, starting at the provided 'startIndex'. // Returns the new copy. // Requires that: // - 'startIndex + len <= self.length' // The length of the substring is: 'len' function substr(bytes memory self, uint256 startIndex, uint256 len) internal pure returns (bytes memory) { require(startIndex + len <= self.length); if (len == 0) { return ""; } uint256 addr = Memory.dataPtr(self); return Memory.toBytes(addr + startIndex, len); } // Combines 'self' and 'other' into a single array. // Returns the concatenated arrays: // [self[0], self[1], ... , self[self.length - 1], other[0], other[1], ... , other[other.length - 1]] // The length of the new array is 'self.length + other.length' function concat(bytes memory self, bytes memory other) internal pure returns (bytes memory) { bytes memory ret = new bytes(self.length + other.length); uint256 src; uint256 srcLen; (src, srcLen) = Memory.fromBytes(self); uint256 src2; uint256 src2Len; (src2, src2Len) = Memory.fromBytes(other); uint256 dest; (dest,) = Memory.fromBytes(ret); uint256 dest2 = dest + srcLen; Memory.copy(src, dest, srcLen); Memory.copy(src2, dest2, src2Len); return ret; } function toBytes32(bytes memory self) internal pure returns (bytes32 out) { require(self.length >= 32, "Bytes:: toBytes32: data is to short."); assembly { out := mload(add(self, 32)) } } function toBytes16(bytes memory self, uint256 offset) internal pure returns (bytes16 out) { for (uint256 i = 0; i < 16; i++) { out |= bytes16(bytes1(self[offset + i]) & 0xFF) >> (i * 8); } } function toBytes8(bytes memory self, uint256 offset) internal pure returns (bytes8 out) { for (uint256 i = 0; i < 8; i++) { out |= bytes8(bytes1(self[offset + i]) & 0xFF) >> (i * 8); } } function toBytes4(bytes memory self, uint256 offset) internal pure returns (bytes4) { bytes4 out; for (uint256 i = 0; i < 4; i++) { out |= bytes4(self[offset + i] & 0xFF) >> (i * 8); } return out; } function toBytes2(bytes memory self, uint256 offset) internal pure returns (bytes2) { bytes2 out; for (uint256 i = 0; i < 2; i++) { out |= bytes2(self[offset + i] & 0xFF) >> (i * 8); } return out; } function removeLeadingZero(bytes memory data) internal pure returns (bytes memory) { uint256 length = data.length; uint256 startIndex = 0; for (uint256 i = 0; i < length; i++) { if (data[i] != 0) { startIndex = i; break; } } return substr(data, startIndex); } function removeEndingZero(bytes memory data) internal pure returns (bytes memory) { uint256 length = data.length; uint256 endIndex = 0; for (uint256 i = length - 1; i >= 0; i--) { if (data[i] != 0) { endIndex = i; break; } } return substr(data, 0, endIndex + 1); } function reverse(bytes memory inbytes) internal pure returns (bytes memory) { uint256 inlength = inbytes.length; bytes memory outbytes = new bytes(inlength); for (uint256 i = 0; i <= inlength - 1; i++) { outbytes[i] = inbytes[inlength - i - 1]; } return outbytes; } }
pragma solidity >=0.6.2; import './IUniswapV2Router01.sol'; interface IUniswapV2Router02 is IUniswapV2Router01 { function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; }
// Copyright (C) Polytope Labs Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma solidity 0.8.17; import {ICallDispatcher} from "../interfaces/ICallDispatcher.sol"; struct CallDispatcherParams { // contract to call address target; // target contract calldata bytes data; } /** * @title The CallDispatcher * @author Polytope Labs ([email protected]) * * @notice This contract is used to dispatch calls to other contracts. */ contract CallDispatcher is ICallDispatcher { /** * @dev reverts if the target is not a contract or if any of the calls reverts. */ function dispatch(bytes memory encoded) external { CallDispatcherParams[] memory calls = abi.decode(encoded, (CallDispatcherParams[])); uint256 callsLen = calls.length; for (uint256 i = 0; i < callsLen; ++i) { CallDispatcherParams memory call = calls[i]; uint32 size; address target = call.target; assembly { size := extcodesize(target) } if (size > 0) { (bool success, bytes memory result) = target.call(call.data); if (!success) revert(string(result)); } } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; // The state commiment identifies a commiment to some intermediate state in the state machine. // This contains some metadata about the state machine like it's own timestamp at the time of this commitment. struct StateCommitment { // This timestamp is useful for handling request timeouts. uint256 timestamp; // Overlay trie commitment to all ismp requests & response. bytes32 overlayRoot; // State trie commitment at the given block height bytes32 stateRoot; } // Identifies some state machine height. We allow for a state machine identifier here // as some consensus clients may track multiple, concurrent state machines. struct StateMachineHeight { // the state machine identifier uint256 stateMachineId; // height of this state machine uint256 height; } // An intermediate state in the series of state transitions undergone by a given state machine. struct IntermediateState { // the state machine identifier uint256 stateMachineId; // height of this state machine uint256 height; // state commitment StateCommitment commitment; } /** * @title The Ismp ConsensusClient * @author Polytope Labs ([email protected]) * * @notice The consensus client interface responsible for the verification of consensus datagrams. * It's internals are opaque to the ISMP framework allowing it to evolve as needed. */ interface IConsensusClient { // @dev Given some opaque consensus proof, produce the new consensus state and newly finalized intermediate states. function verifyConsensus( bytes memory trustedState, bytes memory proof ) external returns (bytes memory, IntermediateState memory); }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 // Outcome of a successfully verified merkle-patricia proof struct StorageValue { // the storage key bytes key; // the encoded value bytes value; } /// @title A representation of a Merkle tree node struct Node { // Distance of the node to the leftmost node uint256 k_index; // A hash of the node itself bytes32 node; } /// @title A representation of a MerkleMountainRange leaf struct MmrLeaf { // the leftmost index of a node uint256 k_index; // The position in the tree uint256 leaf_index; // The hash of the position in the tree bytes32 hash; } struct Iterator { uint256 offset; bytes32[] data; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @dev Interface of the EIP5982 standard, as defined in * https://github.com/polytope-labs/EIPs/blob/master/EIPS/eip-5982.md * * The EIP-165 identifier of this interface is 0x6bb9cd16 */ interface IERC_ACL_CORE { function hasRole(bytes32 role, address account) external view returns (bool); function grantRole(bytes32 role, address account) external; function revokeRole(bytes32 role, address account) external; function changeAdmin(address newAdmin) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Storage.sol) pragma solidity ^0.8.0; import "./ERC165.sol"; /** * @dev Storage based implementation of the {IERC165} interface. * * Contracts may inherit from this and call {_registerInterface} to declare * their support of an interface. */ abstract contract ERC165Storage is ERC165 { /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return super.supportsInterface(interfaceId) || _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See {IERC165-supportsInterface}. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal virtual { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 library Memory { uint256 internal constant WORD_SIZE = 32; // Compares the 'len' bytes starting at address 'addr' in memory with the 'len' // bytes starting at 'addr2'. // Returns 'true' if the bytes are the same, otherwise 'false'. function equals(uint256 addr, uint256 addr2, uint256 len) internal pure returns (bool equal) { assembly { equal := eq(keccak256(addr, len), keccak256(addr2, len)) } } // Compares the 'len' bytes starting at address 'addr' in memory with the bytes stored in // 'bts'. It is allowed to set 'len' to a lower value then 'bts.length', in which case only // the first 'len' bytes will be compared. // Requires that 'bts.length >= len' function equals(uint256 addr, uint256 len, bytes memory bts) internal pure returns (bool equal) { require(bts.length >= len); uint256 addr2; assembly { addr2 := add(bts, /*BYTES_HEADER_SIZE*/ 32) } return equals(addr, addr2, len); } // Returns a memory pointer to the data portion of the provided bytes array. function dataPtr(bytes memory bts) internal pure returns (uint256 addr) { assembly { addr := add(bts, /*BYTES_HEADER_SIZE*/ 32) } } // Creates a 'bytes memory' variable from the memory address 'addr', with the // length 'len'. The function will allocate new memory for the bytes array, and // the 'len bytes starting at 'addr' will be copied into that new memory. function toBytes(uint256 addr, uint256 len) internal pure returns (bytes memory bts) { bts = new bytes(len); uint256 btsptr; assembly { btsptr := add(bts, /*BYTES_HEADER_SIZE*/ 32) } copy(addr, btsptr, len); } // Copies 'self' into a new 'bytes memory'. // Returns the newly created 'bytes memory' // The returned bytes will be of length '32'. function toBytes(bytes32 self) internal pure returns (bytes memory bts) { bts = new bytes(32); assembly { mstore(add(bts, /*BYTES_HEADER_SIZE*/ 32), self) } } // Copy 'len' bytes from memory address 'src', to address 'dest'. // This function does not check the or destination, it only copies // the bytes. function copy(uint256 src, uint256 dest, uint256 len) internal pure { // Copy word-length chunks while possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } dest += WORD_SIZE; src += WORD_SIZE; } // Copy remaining bytes uint256 mask = len == 0 ? 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff : 256 ** (WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) let destpart := and(mload(dest), mask) mstore(dest, or(destpart, srcpart)) } } // This function does the same as 'dataPtr(bytes memory)', but will also return the // length of the provided bytes array. function fromBytes(bytes memory bts) internal pure returns (uint256 addr, uint256 len) { len = bts.length; assembly { addr := add(bts, /*BYTES_HEADER_SIZE*/ 32) } } }
pragma solidity >=0.6.2; interface IUniswapV2Router01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB, uint liquidity); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB); function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountToken, uint amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountA, uint amountB); function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountToken, uint amountETH); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); }
// Copyright (C) Polytope Labs Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma solidity 0.8.17; /** * @title The ICallDispatcher * @author Polytope Labs ([email protected]) * * @notice This interface is used to dispatch untrusted call(s) */ interface ICallDispatcher { /* * @dev Dispatch the encoded call(s) */ function dispatch(bytes memory params) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "@polytope-labs/ismp-solidity/=node_modules/@polytope-labs/ismp-solidity/interfaces/", "openzeppelin/=node_modules/openzeppelin-solidity/contracts/", "@polytope-labs/solidity-merkle-trees/=node_modules/@polytope-labs/solidity-merkle-trees/src/", "@polytope-labs/erc6160/=node_modules/@polytope-labs/erc6160/src/", "@uniswap/v2-periphery/=node_modules/@uniswap/v2-periphery/", "stringutils/=lib/solidity-stringutils/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "solidity-stringutils/=lib/solidity-stringutils/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
[{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InconsistentState","type":"error"},{"inputs":[],"name":"InvalidAddressLength","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"UnauthorizedAccount","type":"error"},{"inputs":[],"name":"UnauthorizedAction","type":"error"},{"inputs":[],"name":"UnexpectedCall","type":"error"},{"inputs":[],"name":"UnknownAsset","type":"error"},{"inputs":[],"name":"UnsupportedChain","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AssetAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"commitment","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"from","type":"bytes32"},{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":true,"internalType":"bytes32","name":"assetId","type":"bytes32"}],"name":"AssetReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"commitment","type":"bytes32"},{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":true,"internalType":"bytes32","name":"assetId","type":"bytes32"}],"name":"AssetRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"erc20","type":"address"},{"indexed":false,"internalType":"address","name":"erc6160","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"bytes32","name":"assetId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"initialSupply","type":"uint256"},{"indexed":false,"internalType":"address","name":"beneficiary","type":"address"}],"name":"AssetRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"assetId","type":"bytes32"}],"name":"AssetRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"to","type":"bytes32"},{"indexed":false,"internalType":"string","name":"dest","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"commitment","type":"bytes32"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"bytes32","name":"assetId","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"redeem","type":"bool"}],"name":"AssetTeleported","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"chain","type":"string"},{"indexed":false,"internalType":"address","name":"moduleId","type":"address"}],"name":"NewContractInstance","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"host","type":"address"},{"internalType":"address","name":"dispatcher","type":"address"}],"indexed":false,"internalType":"struct TokenGatewayParams","name":"oldParams","type":"tuple"},{"components":[{"internalType":"address","name":"host","type":"address"},{"internalType":"address","name":"dispatcher","type":"address"}],"indexed":false,"internalType":"struct TokenGatewayParams","name":"newParams","type":"tuple"}],"name":"ParamsUpdated","type":"event"},{"inputs":[{"internalType":"bytes32","name":"assetId","type":"bytes32"}],"name":"erc20","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assetId","type":"bytes32"}],"name":"erc6160","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"host","type":"address"},{"internalType":"address","name":"dispatcher","type":"address"}],"internalType":"struct TokenGatewayParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"erc20","type":"address"},{"internalType":"address","name":"erc6160","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"address","name":"beneficiary","type":"address"}],"internalType":"struct AssetMetadata[]","name":"assets","type":"tuple[]"}],"internalType":"struct TokenGatewayParamsExt","name":"teleportParams","type":"tuple"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"destination","type":"bytes"}],"name":"instance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IncomingPostRequest","name":"incoming","type":"tuple"}],"name":"onAccept","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct GetRequest","name":"request","type":"tuple"},{"components":[{"internalType":"bytes","name":"key","type":"bytes"},{"internalType":"bytes","name":"value","type":"bytes"}],"internalType":"struct StorageValue[]","name":"values","type":"tuple[]"}],"internalType":"struct GetResponse","name":"response","type":"tuple"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IncomingGetResponse","name":"","type":"tuple"}],"name":"onGetResponse","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct GetRequest","name":"","type":"tuple"}],"name":"onGetTimeout","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"}],"name":"onPostRequestTimeout","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct PostResponse","name":"response","type":"tuple"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct IncomingPostResponse","name":"","type":"tuple"}],"name":"onPostResponse","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct PostResponse","name":"","type":"tuple"}],"name":"onPostResponseTimeout","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"params","outputs":[{"components":[{"internalType":"address","name":"host","type":"address"},{"internalType":"address","name":"dispatcher","type":"address"}],"internalType":"struct TokenGatewayParams","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"relayerFee","type":"uint256"},{"internalType":"bytes32","name":"assetId","type":"bytes32"},{"internalType":"bool","name":"redeem","type":"bool"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"timeout","type":"uint64"},{"internalType":"uint256","name":"nativeCost","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct TeleportParams","name":"teleportParams","type":"tuple"}],"name":"teleport","outputs":[],"stateMutability":"payable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162004f0338038062004f0383398101604081905262000034916200005a565b600280546001600160a01b0319166001600160a01b03929092169190911790556200008c565b6000602082840312156200006d57600080fd5b81516001600160a01b03811681146200008557600080fd5b9392505050565b614e67806200009c6000396000f3fe608060405260043610620000b55760003560e01c806377ea4221116200006c57806377ea422114620001db57806386f28b751462000200578063b2a01bf51462000217578063bc0dd4471462000236578063cff0ab96146200025b578063d0fff36614620002ac57600080fd5b80630bc37bab14620000ba5780630bddd96c14620000e15780630fee32ce146200012357806344ab20f814620001485780636277e51614620001675780636967197a14620001a1575b600080fd5b348015620000c757600080fd5b50620000df620000d9366004620027fc565b620002cb565b005b348015620000ee57600080fd5b50620001066200010036600462002834565b62000320565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156200013057600080fd5b50620000df62000142366004620028aa565b62000378565b3480156200015557600080fd5b50620000df620000d936600462002adb565b3480156200017457600080fd5b50620001066200018636600462002ca3565b6000908152600360205260409020546001600160a01b031690565b348015620001ae57600080fd5b5062000106620001c036600462002ca3565b6000908152600460205260409020546001600160a01b031690565b348015620001e857600080fd5b50620000df620001fa36600462002cbd565b62000555565b620000df6200021136600462002cfa565b62000657565b3480156200022457600080fd5b50620000df620000d936600462002d38565b3480156200024357600080fd5b50620000df6200025536600462002dc5565b62000e24565b3480156200026857600080fd5b50604080518082018252600080825260209182018190528251808401909352546001600160a01b03908116835260015416908201526040516200011a919062002e02565b348015620002b957600080fd5b50620000df620000d936600462002e27565b620002d5620010a7565b6001600160a01b0316336001600160a01b03161462000307576040516354bff84560e11b815260040160405180910390fd5b6040516302cbc79f60e01b815260040160405180910390fd5b6000806005600085856040516200033992919062002e5f565b60408051918290039091208252602082019290925201600020546001600160a01b0316905080156200036c57806200036e565b305b9150505b92915050565b6000546001600160a01b0316338114620003a55760405163421c007d60e11b815260040160405180910390fd5b6000620003b3838062002e6f565b620003c39060c081019062002e90565b6000818110620003d757620003d762002ee0565b919091013560f81c90506005811115620003f557620003f562002ef6565b905060008160058111156200040e576200040e62002ef6565b03620004565760a162000422848062002e6f565b620004329060c081019062002e90565b905011156200044b5762000446836200119d565b505050565b62000446836200146b565b60018160058111156200046d576200046d62002ef6565b0362000489576200044662000483848062002e6f565b62001599565b6002816005811115620004a057620004a062002ef6565b03620004bc5762000446620004b6848062002e6f565b620016db565b6003816005811115620004d357620004d362002ef6565b03620004ef5762000446620004e9848062002e6f565b62001823565b600481600581111562000506576200050662002ef6565b036200052257620004466200051c848062002e6f565b620019d2565b600581600581111562000539576200053962002ef6565b036200044657620004466200054f848062002e6f565b62001b93565b6002546001600160a01b0316338114620005825760405163421c007d60e11b815260040160405180910390fd5b81600062000591828262002f2c565b50620005b89050620005a7604084018462002f65565b620005b2916200306b565b62001caa565b6000546040805163647846a560e01b8152905162000643926001600160a01b03169163647846a59160048083019260209291908290030181865afa15801562000605573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200062b9190620030e7565b6200063a602085018562003107565b60001962001eeb565b5050600280546001600160a01b0319169055565b60808101356200067a5760405163d92e233d60e01b815260040160405180910390fd5b80356000036200069d5760405163162908e360e11b815260040160405180910390fd5b6040808201356000908152600460208181528383205460038252848420548454865163647846a560e01b8152965134976001600160a01b0394851697938516969395929094169363647846a5938181019392918290030181865afa1580156200070a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007309190620030e7565b90506001600160a01b038316158015906200075a575062000758608086016060870162003136565b155b1562000909576000805460408051630b4a282f60e11b815290516001600160a01b0390921691631694505e916004808201926020929091908290030181865afa158015620007ac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007d29190620030e7565b90506000816001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000815573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200083b9190620030e7565b905086358610801590620008605750806001600160a01b0316856001600160a01b0316145b15620008f2576040516000906001600160a01b038316908935908381818185875af1925050503d8060008114620008b4576040519150601f19603f3d011682016040523d82523d6000602084013e620008b9565b606091505b5050905080620008dc57604051633e94cfa960e01b815260040160405180910390fd5b620008e98835886200316c565b96505062000901565b620009018533308a3562001fd7565b50506200099a565b6001600160a01b038216156200098157604051632770a7eb60e21b8152336004820152853560248201526001600160a01b03831690639dc29fac90604401600060405180830381600087803b1580156200096257600080fd5b505af115801562000977573d6000803e3d6000fd5b505050506200099a565b60405163c97d95cf60e01b815260040160405180910390fd5b600080620009ad61010088018862002e90565b90501162000a40576040805160a08101825287358152878201356020820152908101620009e16080890160608a0162003136565b15158152602001338152608088810135602092830152604080518451818501529284015183820152830151151560608084019190915283015182820152919091015160a082015260c00160405160208183030381529060405262000aeb565b6040805160c0810182528735815287820135602082015290810162000a6c6080890160608a0162003136565b151581526020013381526080880135602082015260400162000a9361010089018962002e90565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505091525060405162000adb9190602001620031d6565b6040516020818303038152906040525b90508060405160200162000b00919062003227565b60408051601f1981840301815260c0830190915291506000908062000b2960a08a018a62002e90565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060200162000b766200010060a08b018b62002e90565b60405160200162000b9a919060609190911b6001600160601b031916815260140190565b60408051601f19818403018152918152908252602082018590520162000bc760e08a0160c08b016200324f565b6001600160401b0316815260208981013590820152336040909101529050600060e0880135871080159062000c00575060008860e00135115b1562000c8c5760005460405163b8f3e8f560e01b81526001600160a01b039091169063b8f3e8f59060e08b01359062000c3e9086906004016200326d565b60206040518083038185885af115801562000c5d573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019062000c84919062003307565b905062000da8565b8251600080546040805163641d729d60e01b8152905192936020808e01359491936001600160a01b03169263641d729d92600480830193928290030181865afa15801562000cde573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d04919062003307565b62000d10919062003321565b62000d1c91906200333b565b905062000d2c8533308462001fd7565b60005460405163b8f3e8f560e01b81526001600160a01b039091169063b8f3e8f59062000d5e9086906004016200326d565b6020604051808303816000875af115801562000d7e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000da4919062003307565b9150505b6040880135337f07d0e7e31f460a5025fe4913407d890186747d91632fe9d1ef4666cc5e01d02d60808b013562000de360a08d018d62002e90565b8d60000135878f606001602081019062000dfe919062003136565b60405162000e129695949392919062003351565b60405180910390a35050505050505050565b6000546001600160a01b031633811462000e515760405163421c007d60e11b815260040160405180910390fd5b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915260a162000e8d60c085018562002e90565b9050111562000f0e57600062000ea760c085018562002e90565b62000eb7916001908290620033a1565b81019062000ec69190620033cd565b90506040518060a00160405280826000015181526020018260200151815260200182604001511515815260200182606001518152602001826080015181525091505062000f3f565b62000f1d60c084018462002e90565b62000f2d916001908290620033a1565b81019062000f3c919062003480565b90505b60208181018051600090815260048352604080822054925182526003909352919091205460608301516001600160a01b039283169290911690821580159062000f8a57508360400151155b1562000fa75762000fa18382866000015162002011565b6200103e565b6001600160a01b03821615620010255783516040516340c10f1960e01b81526001600160a01b0383811660048301526024820192909252908316906340c10f1990604401600060405180830381600087803b1580156200100657600080fd5b505af11580156200101b573d6000803e3d6000fd5b505050506200103e565b604051633e94cfa960e01b815260040160405180910390fd5b602084015184516001600160a01b038316907f1f609d15753917f8d3af09955817e394e94d4af7065b94dd780583ee0038f98f9062001087620010818b620034fd565b62002043565b6040805192835260208301919091520160405180910390a3505050505050565b60004662aa36a78114620010e55762066eee8114620011025762aa37dc81146200111f5762014a3481146200113c5760618114620011595762001171565b73f1c7a386325b7d22025d7542b28ee881cdf107b3915062001171565b73286e1fe1c323ee626be802b13a5184b588ed14cb915062001171565b73625c531a56db772cc36313d0a0114956ad8b56c2915062001171565b73ae9f490ee05588fdd857a078cfc1f5f30ae7185f915062001171565b73eb8977edcda5fabdcddeb39861df25e8821a9e9b91505b506001600160a01b0381166200119a5760405163d21eab3760e01b815260040160405180910390fd5b90565b620011a9818062002e6f565b6040516001600160601b03193060601b16602082015260009062001228906034015b60408051601f19818403018152919052620011ea606085018562002e90565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200205e9050565b158015620012ce57506200127f62001244606084018462002e90565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200209092505050565b6001600160a01b03166005600062001298858062002e90565b604051620012a892919062002e5f565b60408051918290039091208252602082019290925201600020546001600160a01b031614155b90508015620012f05760405163421c007d60e11b815260040160405180910390fd5b6000620012fe848062002e6f565b6200130e9060c081019062002e90565b6200131e916001908290620033a1565b8101906200132d9190620033cd565b905060006200134c62001341868062002e6f565b6200108190620034fd565b9050620013956040518060a001604052808460000151815260200184602001518152602001846040015115158152602001846060015181526020018460800151815250620020bd565b60015460a083015160405163156fffe360e31b81526001600160a01b039092169163ab7fff1891620013ca916004016200350b565b600060405180830381600087803b158015620013e557600080fd5b505af1158015620013fa573d6000803e3d6000fd5b5050505081602001516200140f836080015190565b6001600160a01b031683606001517fe9bb1461eb40bd68483bb0decc9cc52b73f51bada078eff01165a97f2377bfe68560000151856040516200145c929190918252602082015260400190565b60405180910390a45050505050565b62001477818062002e6f565b6040516001600160601b03193060601b1660208201526000906200149e90603401620011cb565b158015620015095750620014ba62001244606084018462002e90565b6001600160a01b031660056000620014d3858062002e90565b604051620014e392919062002e5f565b60408051918290039091208252602082019290925201600020546001600160a01b031614155b905080156200152b5760405163421c007d60e11b815260040160405180910390fd5b600062001539848062002e6f565b620015499060c081019062002e90565b62001559916001908290620033a1565b81019062001568919062003480565b905060006200157c62001341868062002e6f565b90506200158982620020bd565b602082015160808301516200140f565b6000805460408051622f3b1f60e11b8152905162001619936001600160a01b0390931692625e763e92600480820193918290030181865afa158015620015e3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200160d919081019062003520565b620011ea838062002e90565b620016375760405163421c007d60e11b815260040160405180910390fd5b60006200164860c083018362002e90565b62001658916001908290620033a1565b81019062001667919062003596565b90507fa71f7687ff8346b13c6f0923b96164593da1bb1ac8e6c571499fcd041d57245e6000826040516200169d929190620035de565b60405180910390a18051600080546001600160a01b03199081166001600160a01b039384161790915560209092015160018054909316911617905550565b6000805460408051622f3b1f60e11b8152905162001725936001600160a01b0390931692625e763e92600480820193918290030181865afa158015620015e3573d6000803e3d6000fd5b620017435760405163421c007d60e11b815260040160405180910390fd5b604080516001808252818301909252600091816020015b620017af6040518060c0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160608152602001606081526020016000815260200160006001600160a01b031681525090565b8152602001906001900390816200175a579050509050620017d460c083018362002e90565b620017e4916001908290620033a1565b810190620017f3919062003620565b8160008151811062001809576200180962002ee0565b60200260200101819052506200181f8162001caa565b5050565b6000805460408051622f3b1f60e11b815290516200186d936001600160a01b0390931692625e763e92600480820193918290030181865afa158015620015e3573d6000803e3d6000fd5b6200188b5760405163421c007d60e11b815260040160405180910390fd5b60006200189c60c083018362002e90565b620018ac916001908290620033a1565b810190620018bb919062003658565b80515190915060005b81811015620019cc576004600084600001518381518110620018ea57620018ea62002ee0565b6020026020010151815260200190815260200160002060006101000a8154906001600160a01b030219169055600360008460000151838151811062001933576200193362002ee0565b6020026020010151815260200190815260200160002060006101000a8154906001600160a01b0302191690557fe04ea870ffed321c6b17bd99491201ac9ffab5f53d6de97faca5ba5db956fbef8360000151828151811062001999576200199962002ee0565b6020026020010151604051620019b191815260200190565b60405180910390a1620019c48162003729565b9050620018c4565b50505050565b6000805460408051622f3b1f60e11b8152905162001a1c936001600160a01b0390931692625e763e92600480820193918290030181865afa158015620015e3573d6000803e3d6000fd5b62001a3a5760405163421c007d60e11b815260040160405180910390fd5b600062001a4b60c083018362002e90565b62001a5b916001908290620033a1565b81019062001a6a919062003745565b8051600090815260036020908152604090912054908201519192506001600160a01b03908116911662001ab05760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03811662001ad85760405163c97d95cf60e01b815260040160405180910390fd5b60208201516040516308f2839760e41b81526001600160a01b03918216600482015290821690638f28397090602401600060405180830381600087803b15801562001b2257600080fd5b505af115801562001b37573d6000803e3d6000fd5b505050507f82e0cebbbfcea0d10cf649041c20143e863ed85b7e3427ac67cf58dd502426ee81836020015160405162001b869291906001600160a01b0392831681529116602082015260400190565b60405180910390a1505050565b6000805460408051622f3b1f60e11b8152905162001bdd936001600160a01b0390931692625e763e92600480820193918290030181865afa158015620015e3573d6000803e3d6000fd5b62001bfb5760405163421c007d60e11b815260040160405180910390fd5b600062001c0c60c083018362002e90565b62001c1c916001908290620033a1565b81019062001c2b919062003776565b6020818101805183518051908401206000908152600590935260409283902080546001600160a01b0319166001600160a01b039092169190911790558251905191519293507f8ef5d91f436acad15a0b59c5ac183adcd42a0da26cfaceb0fea4791cccfda31b9262001c9e9290620037de565b60405180910390a15050565b805160005b818110156200044657600083828151811062001ccf5762001ccf62002ee0565b6020908102919091018101516060810151805192810192909220815191935091906001600160a01b03161562001d24578060405160200162001d1291906200380a565b60405160208183030381529060405290505b60208301516001600160a01b031662001e30576000823085604001518460405162001d4f9062002487565b62001d5d9392919062003832565b8190604051809103906000f590508015801562001d7e573d6000803e3d6000fd5b506001600160a01b03808216602087015260a0860151919250161580159062001daa5750608084015115155b1562001e2e5760a084015160808501516040516340c10f1960e01b81526001600160a01b038416926340c10f199262001df9926004016001600160a01b03929092168252602082015260400190565b600060405180830381600087803b15801562001e1457600080fd5b505af115801562001e29573d6000803e3d6000fd5b505050505b505b8251600083815260046020908152604080832080546001600160a01b039586166001600160a01b031991821617909155828801805160039094529382902080549390951692169190911790925584519051828601516060870151608088015160a089015195517f13808dd38566fb55d30620d567d45fb743f01fce0f5f87b5869eb2c7420d97329662001ecc96959493928a9290919062003876565b60405180910390a15050508062001ee39062003729565b905062001caf565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801562001f3d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001f63919062003307565b62001f6f91906200333b565b6040516001600160a01b038516602482015260448101829052909150620019cc90859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152620021b0565b6040516001600160a01b0380851660248301528316604482015260648101829052620019cc9085906323b872dd60e01b9060840162001f9f565b6040516001600160a01b0383166024820152604481018290526200044690849063a9059cbb60e01b9060640162001f9f565b600062002050826200228d565b805190602001209050919050565b60008151835114620020735750600062000372565b825160208381018281209186019283209091145b95945050505050565b60008151601414620020b557604051636616760160e11b815260040160405180910390fd5b506014015190565b6020808201805160009081526004835260408082205492518252600390935291909120546001600160a01b0391821691168115801590620020ff575082604001515b156200211e57620004468262002116856080015190565b855162002011565b6001600160a01b038116156200098157806001600160a01b03166340c10f1962002149856080015190565b855160405160e084901b6001600160e01b03191681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156200219257600080fd5b505af1158015620021a7573d6000803e3d6000fd5b50505050505050565b600062002207826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620022e09092919063ffffffff16565b805190915015620004465780806020019051810190620022289190620038d8565b620004465760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084015b60405180910390fd5b60608160000151826020015183604001518460a00151856060015186608001518760c00151604051602001620022ca9796959493929190620038f8565b6040516020818303038152906040529050919050565b6060620022f18484600085620022fb565b90505b9392505050565b6060824710156200235e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162002284565b600080866001600160a01b031685876040516200237c919062003999565b60006040518083038185875af1925050503d8060008114620023bb576040519150601f19603f3d011682016040523d82523d6000602084013e620023c0565b606091505b5091509150620023d387838387620023e0565b925050505b949350505050565b60608315620024545782516000036200244c576001600160a01b0385163b6200244c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162002284565b5081620023d8565b620023d883838151156200246b5781518083602001fd5b8060405162461bcd60e51b81526004016200228491906200350b565b61148480620039ae83390190565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715620024d057620024d062002495565b60405290565b60405161010081016001600160401b0381118282101715620024d057620024d062002495565b604080519081016001600160401b0381118282101715620024d057620024d062002495565b60405160c081016001600160401b0381118282101715620024d057620024d062002495565b604051602081016001600160401b0381118282101715620024d057620024d062002495565b604051601f8201601f191681016001600160401b038111828210171562002596576200259662002495565b604052919050565b60006001600160401b03821115620025ba57620025ba62002495565b50601f01601f191660200190565b600082601f830112620025da57600080fd5b8135620025f1620025eb826200259e565b6200256b565b8181528460208386010111156200260757600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160401b03811681146200263c57600080fd5b919050565b600060e082840312156200265457600080fd5b6200265e620024ab565b905081356001600160401b03808211156200267857600080fd5b6200268685838601620025c8565b835260208401359150808211156200269d57600080fd5b620026ab85838601620025c8565b6020840152620026be6040850162002624565b60408401526060840135915080821115620026d857600080fd5b620026e685838601620025c8565b606084015260808401359150808211156200270057600080fd5b6200270e85838601620025c8565b60808401526200272160a0850162002624565b60a084015260c08401359150808211156200273b57600080fd5b506200274a84828501620025c8565b60c08301525092915050565b6000606082840312156200276957600080fd5b604051606081016001600160401b0382821081831117156200278f576200278f62002495565b816040528293508435915080821115620027a857600080fd5b620027b68683870162002641565b83526020850135915080821115620027cd57600080fd5b50620027dc85828601620025c8565b602083015250620027f06040840162002624565b60408201525092915050565b6000602082840312156200280f57600080fd5b81356001600160401b038111156200282657600080fd5b6200036e8482850162002756565b600080602083850312156200284857600080fd5b82356001600160401b03808211156200286057600080fd5b818501915085601f8301126200287557600080fd5b8135818111156200288557600080fd5b8660208285010111156200289857600080fd5b60209290920196919550909350505050565b600060208284031215620028bd57600080fd5b81356001600160401b03811115620028d457600080fd5b820160408185031215620022f457600080fd5b6001600160a01b0381168114620028fd57600080fd5b50565b80356200263c81620028e7565b60006001600160401b0382111562002929576200292962002495565b5060051b60200190565b600082601f8301126200294557600080fd5b8135602062002958620025eb836200290d565b82815260059290921b840181019181810190868411156200297857600080fd5b8286015b84811015620029bc5780356001600160401b038111156200299d5760008081fd5b620029ad8986838b0101620025c8565b8452509183019183016200297c565b509695505050505050565b60006101008284031215620029db57600080fd5b620029e5620024d6565b905081356001600160401b0380821115620029ff57600080fd5b62002a0d85838601620025c8565b8352602084013591508082111562002a2457600080fd5b62002a3285838601620025c8565b602084015262002a456040850162002624565b604084015262002a586060850162002900565b606084015262002a6b6080850162002624565b608084015260a084013591508082111562002a8557600080fd5b62002a938583860162002933565b60a084015262002aa660c0850162002624565b60c084015260e084013591508082111562002ac057600080fd5b5062002acf84828501620025c8565b60e08301525092915050565b60006020828403121562002aee57600080fd5b6001600160401b03808335111562002b0557600080fd5b823583016040818603121562002b1a57600080fd5b62002b24620024fc565b828235111562002b3357600080fd5b813582016040818803121562002b4857600080fd5b62002b52620024fc565b848235111562002b6157600080fd5b62002b708883358401620029c7565b8152846020830135111562002b8457600080fd5b60208201358201915087601f83011262002b9d57600080fd5b62002bad620025eb83356200290d565b82358082526020808301929160051b8501018a81111562002bcd57600080fd5b602085015b8181101562002c7857888135111562002bea57600080fd5b803586016040818e03601f1901121562002c0357600080fd5b62002c0d620024fc565b8a6020830135111562002c1f57600080fd5b62002c338e602080850135850101620025c8565b81528a6040830135111562002c4757600080fd5b62002c5c8e60206040850135850101620025c8565b6020820152808652505060208401935060208101905062002bd2565b50508060208401525050808352505062002c956020830162002900565b602082015295945050505050565b60006020828403121562002cb657600080fd5b5035919050565b60006020828403121562002cd057600080fd5b81356001600160401b0381111562002ce757600080fd5b820160608185031215620022f457600080fd5b60006020828403121562002d0d57600080fd5b81356001600160401b0381111562002d2457600080fd5b82016101208185031215620022f457600080fd5b60006020828403121562002d4b57600080fd5b81356001600160401b038082111562002d6357600080fd5b908301906040828603121562002d7857600080fd5b62002d82620024fc565b82358281111562002d9257600080fd5b62002da08782860162002756565b8252506020830135925062002db583620028e7565b6020810192909252509392505050565b60006020828403121562002dd857600080fd5b81356001600160401b0381111562002def57600080fd5b820160e08185031215620022f457600080fd5b6040810162000372828480516001600160a01b03908116835260209182015116910152565b60006020828403121562002e3a57600080fd5b81356001600160401b0381111562002e5157600080fd5b6200036e84828501620029c7565b8183823760009101908152919050565b6000823560de1983360301811262002e8657600080fd5b9190910192915050565b6000808335601e1984360301811262002ea857600080fd5b8301803591506001600160401b0382111562002ec357600080fd5b60200191503681900382131562002ed957600080fd5b9250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b80546001600160a01b0319166001600160a01b0392909216919091179055565b813562002f3981620028e7565b62002f45818362002f0c565b50602082013562002f5681620028e7565b62000446816001840162002f0c565b6000808335601e1984360301811262002f7d57600080fd5b8301803591506001600160401b0382111562002f9857600080fd5b6020019150600581901b360382131562002ed957600080fd5b600060c0828403121562002fc457600080fd5b62002fce62002521565b905062002fdb8262002900565b815262002feb6020830162002900565b602082015260408201356001600160401b03808211156200300b57600080fd5b6200301985838601620025c8565b604084015260608401359150808211156200303357600080fd5b506200304284828501620025c8565b606083015250608082013560808201526200306060a0830162002900565b60a082015292915050565b60006200307c620025eb846200290d565b80848252602080830192508560051b8501368111156200309b57600080fd5b855b81811015620030db5780356001600160401b03811115620030be5760008081fd5b620030cc36828a0162002fb1565b8652509382019382016200309d565b50919695505050505050565b600060208284031215620030fa57600080fd5b8151620022f481620028e7565b6000602082840312156200311a57600080fd5b8135620022f481620028e7565b8015158114620028fd57600080fd5b6000602082840312156200314957600080fd5b8135620022f48162003127565b634e487b7160e01b600052601160045260246000fd5b8181038181111562000372576200037262003156565b60005b838110156200319f57818101518382015260200162003185565b50506000910152565b60008151808452620031c281602086016020860162003182565b601f01601f19169290920160200192915050565b60208152815160208201526020820151604082015260408201511515606082015260608201516080820152608082015160a0820152600060a083015160c0808401526200036e60e0840182620031a8565b60008152600082516200324281600185016020870162003182565b9190910160010192915050565b6000602082840312156200326257600080fd5b620022f48262002624565b602081526000825160c060208401526200328b60e0840182620031a8565b90506020840151601f1980858403016040860152620032ab8383620031a8565b9250604086015191508085840301606086015250620032cb8282620031a8565b9150506001600160401b036060850151166080840152608084015160a084015260018060a01b0360a08501511660c08401528091505092915050565b6000602082840312156200331a57600080fd5b5051919050565b808202811582820484141762000372576200037262003156565b8082018082111562000372576200037262003156565b86815260a060208201528460a0820152848660c0830137600060c08683010152600060c0601f19601f88011683010190508460408301528360608301528215156080830152979650505050505050565b60008085851115620033b257600080fd5b83861115620033c057600080fd5b5050820193919092039150565b600060208284031215620033e057600080fd5b81356001600160401b0380821115620033f857600080fd5b9083019060c082860312156200340d57600080fd5b6200341762002521565b82358152602083013560208201526040830135620034358162003127565b80604083015250606083013560608201526080830135608082015260a0830135828111156200346357600080fd5b6200347187828601620025c8565b60a08301525095945050505050565b600060a082840312156200349357600080fd5b60405160a081018181106001600160401b0382111715620034b857620034b862002495565b806040525082358152602083013560208201526040830135620034db8162003127565b6040820152606083810135908201526080928301359281019290925250919050565b600062000372368362002641565b602081526000620022f46020830184620031a8565b6000602082840312156200353357600080fd5b81516001600160401b038111156200354a57600080fd5b8201601f810184136200355c57600080fd5b80516200356d620025eb826200259e565b8181528560208385010111156200358357600080fd5b6200208782602083016020860162003182565b600060408284031215620035a957600080fd5b620035b3620024fc565b8235620035c081620028e7565b81526020830135620035d281620028e7565b60208201529392505050565b82546001600160a01b039081168252600184015416602082015260808101620022f4604083018480516001600160a01b03908116835260209182015116910152565b6000602082840312156200363357600080fd5b81356001600160401b038111156200364a57600080fd5b6200036e8482850162002fb1565b600060208083850312156200366c57600080fd5b82356001600160401b03808211156200368457600080fd5b81850191508282870312156200369957600080fd5b620036a362002546565b823582811115620036b357600080fd5b80840193505086601f840112620036c957600080fd5b82359150620036dc620025eb836200290d565b82815260059290921b83018401918481019088841115620036fc57600080fd5b938501935b838510156200371c5784358252938501939085019062003701565b8252509695505050505050565b6000600182016200373e576200373e62003156565b5060010190565b6000604082840312156200375857600080fd5b62003762620024fc565b823581526020830135620035d281620028e7565b6000602082840312156200378957600080fd5b81356001600160401b0380821115620037a157600080fd5b9083019060408286031215620037b657600080fd5b620037c0620024fc565b823582811115620037d057600080fd5b62002da087828601620025c8565b604081526000620037f36040830185620031a8565b905060018060a01b03831660208301529392505050565b600082516200381e81846020870162003182565b6105cd60f31b920191825250600201919050565b6001600160a01b03841681526060602082018190526000906200385890830185620031a8565b82810360408401526200386c8185620031a8565b9695505050505050565b600060018060a01b03808a168352808916602084015260e06040840152620038a260e0840189620031a8565b8381036060850152620038b68189620031a8565b60808501979097525060a083019490945250911660c090910152949350505050565b600060208284031215620038eb57600080fd5b8151620022f48162003127565b600088516200390c818460208d0162003182565b88519083019062003922818360208d0162003182565b60c089811b6001600160c01b03199081169390920192835288901b166008820152855162003958816010840160208a0162003182565b85519101906200397081601084016020890162003182565b84519101906200398881601084016020880162003182565b016010019998505050505050505050565b6000825162002e868184602087016200318256fe60806040523480156200001157600080fd5b5060405162001484380380620014848339810160408190526200003491620002b3565b81816004620000448382620003cc565b506005620000538282620003cc565b506200006a915063b6ba5da360e01b90506200016a565b6200007c63dd0390b560e01b6200016a565b6200008e637248fa3360e11b6200016a565b50506001600160a01b031660009081527f15e730a082bd931bd9f1fc81c9aa2c9308a74dbdf27de2bec5058a0e60fe64aa602090815260408083208054600160ff1991821681179092557fc9597e0dd7b45d7b4c627952a921a5050cad933a06ad3e737ecde71f09857812845282852080548216831790557f4e686283402f72de62620fd26e24e5a6c7bd1d6067c734dda678ed6e18ad6ab3845282852080548216831790557f30a921b2188042103ab7d696490f6fa125548bb0385c7319673533fb2dce7e5b90935292208054909116909117905562000498565b6001600160e01b03198082169003620001c95760405162461bcd60e51b815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015260640160405180910390fd5b6001600160e01b0319166000908152602081905260409020805460ff19166001179055565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200021657600080fd5b81516001600160401b0380821115620002335762000233620001ee565b604051601f8301601f19908116603f011681019082821181831017156200025e576200025e620001ee565b816040528381526020925086838588010111156200027b57600080fd5b600091505b838210156200029f578582018301518183018401529082019062000280565b600093810190920192909252949350505050565b600080600060608486031215620002c957600080fd5b83516001600160a01b0381168114620002e157600080fd5b60208501519093506001600160401b0380821115620002ff57600080fd5b6200030d8783880162000204565b935060408601519150808211156200032457600080fd5b50620003338682870162000204565b9150509250925092565b600181811c908216806200035257607f821691505b6020821081036200037357634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003c757600081815260208120601f850160051c81016020861015620003a25750805b601f850160051c820191505b81811015620003c357828155600101620003ae565b5050505b505050565b81516001600160401b03811115620003e857620003e8620001ee565b6200040081620003f984546200033d565b8462000379565b602080601f8311600181146200043857600084156200041f5750858301515b600019600386901b1c1916600185901b178555620003c3565b600085815260208120601f198616915b82811015620004695788860151825594840194600190910190840162000448565b5085821015620004885787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b610fdc80620004a86000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c80638f283970116100b8578063a9059cbb1161007c578063a9059cbb146102d0578063c5b66dc9146102e3578063d539139314610309578063d547741f14610330578063dd62ed3e14610343578063ea35f36c1461035657600080fd5b80638f2839701461025657806391d148541461026957806395d89b41146102a25780639dc29fac146102aa578063a457c2d7146102bd57600080fd5b8063282c51f31161010a578063282c51f3146101bc5780632f2ff15d146101e3578063313ce567146101f8578063395093511461020757806340c10f191461021a57806370a082311461022d57600080fd5b806301ffc9a71461014757806306fdde031461016f578063095ea7b31461018457806318160ddd1461019757806323b872dd146101a9575b600080fd5b61015a610155366004610d99565b61037c565b60405190151581526020015b60405180910390f35b61017761038d565b6040516101669190610dca565b61015a610192366004610e34565b61041f565b6003545b604051908152602001610166565b61015a6101b7366004610e5e565b610437565b61019b7fe7ba54b021ea26ee9c797c92a7485e5bb59d2b07365aae349635a1bf8d0bd7af81565b6101f66101f1366004610e9a565b61045b565b005b60405160128152602001610166565b61015a610215366004610e34565b6104c5565b6101f6610228366004610e34565b6104e7565b61019b61023b366004610ec6565b6001600160a01b031660009081526001602052604090205490565b6101f6610264366004610ec6565b610567565b61015a610277366004610e9a565b60009182526006602090815260408084206001600160a01b0393909316845291905290205460ff1690565b61017761067b565b6101f66102b8366004610e34565b61068a565b61015a6102cb366004610e34565b610706565b61015a6102de366004610e34565b610786565b7fe7ba54b021ea26ee9c797c92a7485e5bb59d2b07365aae349635a1bf8d0bd7af61019b565b61019b7f71c3f5d1e4abab6db588a0fd893947888ebf8abda567a125ca9d5845ef22dda581565b6101f661033e366004610e9a565b610794565b61019b610351366004610ee1565b6107fb565b7f71c3f5d1e4abab6db588a0fd893947888ebf8abda567a125ca9d5845ef22dda561019b565b600061038782610826565b92915050565b60606004805461039c90610f0b565b80601f01602080910402602001604051908101604052809291908181526020018280546103c890610f0b565b80156104155780601f106103ea57610100808354040283529160200191610415565b820191906000526020600020905b8154815290600101906020018083116103f857829003601f168201915b5050505050905090565b60003361042d818585610862565b5060019392505050565b600033610445858285610987565b610450858585610a01565b506001949350505050565b600082815260076020908152604080832033845290915290205460ff166104955760405163521128ff60e01b815260040160405180910390fd5b60009182526006602090815260408084206001600160a01b0390931684529190529020805460ff19166001179055565b60003361042d8185856104d883836107fb565b6104e29190610f45565b610862565b336000908152600080516020610f67833981519152602052604090205460ff1615801561053b57506105397f71c3f5d1e4abab6db588a0fd893947888ebf8abda567a125ca9d5845ef22dda533610277565b155b1561055957604051630782484160e21b815260040160405180910390fd5b6105638282610bac565b5050565b336000908152600080516020610f67833981519152602052604090205460ff1615806105b05750336000908152600080516020610f87833981519152602052604090205460ff16155b156105ce5760405163521128ff60e01b815260040160405180910390fd5b336000908152600080516020610f6783398151915260209081526040808320805460ff19908116909155600080516020610f87833981519152909252909120805490911690556001600160a01b0381166106255750565b6001600160a01b03166000908152600080516020610f67833981519152602090815260408083208054600160ff199182168117909255600080516020610f87833981519152909352922080549091169091179055565b60606005805461039c90610f0b565b336000908152600080516020610f87833981519152602052604090205460ff161580156106de57506106dc7fe7ba54b021ea26ee9c797c92a7485e5bb59d2b07365aae349635a1bf8d0bd7af33610277565b155b156106fc57604051630782484160e21b815260040160405180910390fd5b6105638282610c6d565b6000338161071482866107fb565b9050838110156107795760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6104508286868403610862565b60003361042d818585610a01565b600082815260076020908152604080832033845290915290205460ff166107ce5760405163521128ff60e01b815260040160405180910390fd5b60009182526006602090815260408084206001600160a01b0390931684529190529020805460ff19169055565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b60006301ffc9a760e01b6001600160e01b0319831614806103875750506001600160e01b03191660009081526020819052604090205460ff1690565b6001600160a01b0383166108c45760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610770565b6001600160a01b0382166109255760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610770565b6001600160a01b0383811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b600061099384846107fb565b905060001981146109fb57818110156109ee5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610770565b6109fb8484848403610862565b50505050565b6001600160a01b038316610a655760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610770565b6001600160a01b038216610ac75760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610770565b6001600160a01b03831660009081526001602052604090205481811015610b3f5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610770565b6001600160a01b0380851660008181526001602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610b9f9086815260200190565b60405180910390a36109fb565b6001600160a01b038216610c025760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610770565b8060036000828254610c149190610f45565b90915550506001600160a01b0382166000818152600160209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b038216610ccd5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610770565b6001600160a01b03821660009081526001602052604090205481811015610d415760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610770565b6001600160a01b03831660008181526001602090815260408083208686039055600380548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910161097a565b600060208284031215610dab57600080fd5b81356001600160e01b031981168114610dc357600080fd5b9392505050565b600060208083528351808285015260005b81811015610df757858101830151858201604001528201610ddb565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b0381168114610e2f57600080fd5b919050565b60008060408385031215610e4757600080fd5b610e5083610e18565b946020939093013593505050565b600080600060608486031215610e7357600080fd5b610e7c84610e18565b9250610e8a60208501610e18565b9150604084013590509250925092565b60008060408385031215610ead57600080fd5b82359150610ebd60208401610e18565b90509250929050565b600060208284031215610ed857600080fd5b610dc382610e18565b60008060408385031215610ef457600080fd5b610efd83610e18565b9150610ebd60208401610e18565b600181811c90821680610f1f57607f821691505b602082108103610f3f57634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561038757634e487b7160e01b600052601160045260246000fdfe15e730a082bd931bd9f1fc81c9aa2c9308a74dbdf27de2bec5058a0e60fe64aac9597e0dd7b45d7b4c627952a921a5050cad933a06ad3e737ecde71f09857812a264697066735822122096925c25124dd453b381a457f60ce16902311e20a61a7463a6fa80841b7f653764736f6c63430008110033a26469706673582212209bd14071144e283355300217ee5f2658ab8edcbb2a54176356f5f6d22c1b81f364736f6c63430008110033000000000000000000000000a6ab534d799e30fb71e4f9b0cf768bb49ff9fa64
Deployed Bytecode
0x608060405260043610620000b55760003560e01c806377ea4221116200006c57806377ea422114620001db57806386f28b751462000200578063b2a01bf51462000217578063bc0dd4471462000236578063cff0ab96146200025b578063d0fff36614620002ac57600080fd5b80630bc37bab14620000ba5780630bddd96c14620000e15780630fee32ce146200012357806344ab20f814620001485780636277e51614620001675780636967197a14620001a1575b600080fd5b348015620000c757600080fd5b50620000df620000d9366004620027fc565b620002cb565b005b348015620000ee57600080fd5b50620001066200010036600462002834565b62000320565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156200013057600080fd5b50620000df62000142366004620028aa565b62000378565b3480156200015557600080fd5b50620000df620000d936600462002adb565b3480156200017457600080fd5b50620001066200018636600462002ca3565b6000908152600360205260409020546001600160a01b031690565b348015620001ae57600080fd5b5062000106620001c036600462002ca3565b6000908152600460205260409020546001600160a01b031690565b348015620001e857600080fd5b50620000df620001fa36600462002cbd565b62000555565b620000df6200021136600462002cfa565b62000657565b3480156200022457600080fd5b50620000df620000d936600462002d38565b3480156200024357600080fd5b50620000df6200025536600462002dc5565b62000e24565b3480156200026857600080fd5b50604080518082018252600080825260209182018190528251808401909352546001600160a01b03908116835260015416908201526040516200011a919062002e02565b348015620002b957600080fd5b50620000df620000d936600462002e27565b620002d5620010a7565b6001600160a01b0316336001600160a01b03161462000307576040516354bff84560e11b815260040160405180910390fd5b6040516302cbc79f60e01b815260040160405180910390fd5b6000806005600085856040516200033992919062002e5f565b60408051918290039091208252602082019290925201600020546001600160a01b0316905080156200036c57806200036e565b305b9150505b92915050565b6000546001600160a01b0316338114620003a55760405163421c007d60e11b815260040160405180910390fd5b6000620003b3838062002e6f565b620003c39060c081019062002e90565b6000818110620003d757620003d762002ee0565b919091013560f81c90506005811115620003f557620003f562002ef6565b905060008160058111156200040e576200040e62002ef6565b03620004565760a162000422848062002e6f565b620004329060c081019062002e90565b905011156200044b5762000446836200119d565b505050565b62000446836200146b565b60018160058111156200046d576200046d62002ef6565b0362000489576200044662000483848062002e6f565b62001599565b6002816005811115620004a057620004a062002ef6565b03620004bc5762000446620004b6848062002e6f565b620016db565b6003816005811115620004d357620004d362002ef6565b03620004ef5762000446620004e9848062002e6f565b62001823565b600481600581111562000506576200050662002ef6565b036200052257620004466200051c848062002e6f565b620019d2565b600581600581111562000539576200053962002ef6565b036200044657620004466200054f848062002e6f565b62001b93565b6002546001600160a01b0316338114620005825760405163421c007d60e11b815260040160405180910390fd5b81600062000591828262002f2c565b50620005b89050620005a7604084018462002f65565b620005b2916200306b565b62001caa565b6000546040805163647846a560e01b8152905162000643926001600160a01b03169163647846a59160048083019260209291908290030181865afa15801562000605573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200062b9190620030e7565b6200063a602085018562003107565b60001962001eeb565b5050600280546001600160a01b0319169055565b60808101356200067a5760405163d92e233d60e01b815260040160405180910390fd5b80356000036200069d5760405163162908e360e11b815260040160405180910390fd5b6040808201356000908152600460208181528383205460038252848420548454865163647846a560e01b8152965134976001600160a01b0394851697938516969395929094169363647846a5938181019392918290030181865afa1580156200070a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007309190620030e7565b90506001600160a01b038316158015906200075a575062000758608086016060870162003136565b155b1562000909576000805460408051630b4a282f60e11b815290516001600160a01b0390921691631694505e916004808201926020929091908290030181865afa158015620007ac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007d29190620030e7565b90506000816001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000815573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200083b9190620030e7565b905086358610801590620008605750806001600160a01b0316856001600160a01b0316145b15620008f2576040516000906001600160a01b038316908935908381818185875af1925050503d8060008114620008b4576040519150601f19603f3d011682016040523d82523d6000602084013e620008b9565b606091505b5050905080620008dc57604051633e94cfa960e01b815260040160405180910390fd5b620008e98835886200316c565b96505062000901565b620009018533308a3562001fd7565b50506200099a565b6001600160a01b038216156200098157604051632770a7eb60e21b8152336004820152853560248201526001600160a01b03831690639dc29fac90604401600060405180830381600087803b1580156200096257600080fd5b505af115801562000977573d6000803e3d6000fd5b505050506200099a565b60405163c97d95cf60e01b815260040160405180910390fd5b600080620009ad61010088018862002e90565b90501162000a40576040805160a08101825287358152878201356020820152908101620009e16080890160608a0162003136565b15158152602001338152608088810135602092830152604080518451818501529284015183820152830151151560608084019190915283015182820152919091015160a082015260c00160405160208183030381529060405262000aeb565b6040805160c0810182528735815287820135602082015290810162000a6c6080890160608a0162003136565b151581526020013381526080880135602082015260400162000a9361010089018962002e90565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505091525060405162000adb9190602001620031d6565b6040516020818303038152906040525b90508060405160200162000b00919062003227565b60408051601f1981840301815260c0830190915291506000908062000b2960a08a018a62002e90565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060200162000b766200010060a08b018b62002e90565b60405160200162000b9a919060609190911b6001600160601b031916815260140190565b60408051601f19818403018152918152908252602082018590520162000bc760e08a0160c08b016200324f565b6001600160401b0316815260208981013590820152336040909101529050600060e0880135871080159062000c00575060008860e00135115b1562000c8c5760005460405163b8f3e8f560e01b81526001600160a01b039091169063b8f3e8f59060e08b01359062000c3e9086906004016200326d565b60206040518083038185885af115801562000c5d573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019062000c84919062003307565b905062000da8565b8251600080546040805163641d729d60e01b8152905192936020808e01359491936001600160a01b03169263641d729d92600480830193928290030181865afa15801562000cde573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d04919062003307565b62000d10919062003321565b62000d1c91906200333b565b905062000d2c8533308462001fd7565b60005460405163b8f3e8f560e01b81526001600160a01b039091169063b8f3e8f59062000d5e9086906004016200326d565b6020604051808303816000875af115801562000d7e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000da4919062003307565b9150505b6040880135337f07d0e7e31f460a5025fe4913407d890186747d91632fe9d1ef4666cc5e01d02d60808b013562000de360a08d018d62002e90565b8d60000135878f606001602081019062000dfe919062003136565b60405162000e129695949392919062003351565b60405180910390a35050505050505050565b6000546001600160a01b031633811462000e515760405163421c007d60e11b815260040160405180910390fd5b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915260a162000e8d60c085018562002e90565b9050111562000f0e57600062000ea760c085018562002e90565b62000eb7916001908290620033a1565b81019062000ec69190620033cd565b90506040518060a00160405280826000015181526020018260200151815260200182604001511515815260200182606001518152602001826080015181525091505062000f3f565b62000f1d60c084018462002e90565b62000f2d916001908290620033a1565b81019062000f3c919062003480565b90505b60208181018051600090815260048352604080822054925182526003909352919091205460608301516001600160a01b039283169290911690821580159062000f8a57508360400151155b1562000fa75762000fa18382866000015162002011565b6200103e565b6001600160a01b03821615620010255783516040516340c10f1960e01b81526001600160a01b0383811660048301526024820192909252908316906340c10f1990604401600060405180830381600087803b1580156200100657600080fd5b505af11580156200101b573d6000803e3d6000fd5b505050506200103e565b604051633e94cfa960e01b815260040160405180910390fd5b602084015184516001600160a01b038316907f1f609d15753917f8d3af09955817e394e94d4af7065b94dd780583ee0038f98f9062001087620010818b620034fd565b62002043565b6040805192835260208301919091520160405180910390a3505050505050565b60004662aa36a78114620010e55762066eee8114620011025762aa37dc81146200111f5762014a3481146200113c5760618114620011595762001171565b73f1c7a386325b7d22025d7542b28ee881cdf107b3915062001171565b73286e1fe1c323ee626be802b13a5184b588ed14cb915062001171565b73625c531a56db772cc36313d0a0114956ad8b56c2915062001171565b73ae9f490ee05588fdd857a078cfc1f5f30ae7185f915062001171565b73eb8977edcda5fabdcddeb39861df25e8821a9e9b91505b506001600160a01b0381166200119a5760405163d21eab3760e01b815260040160405180910390fd5b90565b620011a9818062002e6f565b6040516001600160601b03193060601b16602082015260009062001228906034015b60408051601f19818403018152919052620011ea606085018562002e90565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200205e9050565b158015620012ce57506200127f62001244606084018462002e90565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200209092505050565b6001600160a01b03166005600062001298858062002e90565b604051620012a892919062002e5f565b60408051918290039091208252602082019290925201600020546001600160a01b031614155b90508015620012f05760405163421c007d60e11b815260040160405180910390fd5b6000620012fe848062002e6f565b6200130e9060c081019062002e90565b6200131e916001908290620033a1565b8101906200132d9190620033cd565b905060006200134c62001341868062002e6f565b6200108190620034fd565b9050620013956040518060a001604052808460000151815260200184602001518152602001846040015115158152602001846060015181526020018460800151815250620020bd565b60015460a083015160405163156fffe360e31b81526001600160a01b039092169163ab7fff1891620013ca916004016200350b565b600060405180830381600087803b158015620013e557600080fd5b505af1158015620013fa573d6000803e3d6000fd5b5050505081602001516200140f836080015190565b6001600160a01b031683606001517fe9bb1461eb40bd68483bb0decc9cc52b73f51bada078eff01165a97f2377bfe68560000151856040516200145c929190918252602082015260400190565b60405180910390a45050505050565b62001477818062002e6f565b6040516001600160601b03193060601b1660208201526000906200149e90603401620011cb565b158015620015095750620014ba62001244606084018462002e90565b6001600160a01b031660056000620014d3858062002e90565b604051620014e392919062002e5f565b60408051918290039091208252602082019290925201600020546001600160a01b031614155b905080156200152b5760405163421c007d60e11b815260040160405180910390fd5b600062001539848062002e6f565b620015499060c081019062002e90565b62001559916001908290620033a1565b81019062001568919062003480565b905060006200157c62001341868062002e6f565b90506200158982620020bd565b602082015160808301516200140f565b6000805460408051622f3b1f60e11b8152905162001619936001600160a01b0390931692625e763e92600480820193918290030181865afa158015620015e3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200160d919081019062003520565b620011ea838062002e90565b620016375760405163421c007d60e11b815260040160405180910390fd5b60006200164860c083018362002e90565b62001658916001908290620033a1565b81019062001667919062003596565b90507fa71f7687ff8346b13c6f0923b96164593da1bb1ac8e6c571499fcd041d57245e6000826040516200169d929190620035de565b60405180910390a18051600080546001600160a01b03199081166001600160a01b039384161790915560209092015160018054909316911617905550565b6000805460408051622f3b1f60e11b8152905162001725936001600160a01b0390931692625e763e92600480820193918290030181865afa158015620015e3573d6000803e3d6000fd5b620017435760405163421c007d60e11b815260040160405180910390fd5b604080516001808252818301909252600091816020015b620017af6040518060c0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160608152602001606081526020016000815260200160006001600160a01b031681525090565b8152602001906001900390816200175a579050509050620017d460c083018362002e90565b620017e4916001908290620033a1565b810190620017f3919062003620565b8160008151811062001809576200180962002ee0565b60200260200101819052506200181f8162001caa565b5050565b6000805460408051622f3b1f60e11b815290516200186d936001600160a01b0390931692625e763e92600480820193918290030181865afa158015620015e3573d6000803e3d6000fd5b6200188b5760405163421c007d60e11b815260040160405180910390fd5b60006200189c60c083018362002e90565b620018ac916001908290620033a1565b810190620018bb919062003658565b80515190915060005b81811015620019cc576004600084600001518381518110620018ea57620018ea62002ee0565b6020026020010151815260200190815260200160002060006101000a8154906001600160a01b030219169055600360008460000151838151811062001933576200193362002ee0565b6020026020010151815260200190815260200160002060006101000a8154906001600160a01b0302191690557fe04ea870ffed321c6b17bd99491201ac9ffab5f53d6de97faca5ba5db956fbef8360000151828151811062001999576200199962002ee0565b6020026020010151604051620019b191815260200190565b60405180910390a1620019c48162003729565b9050620018c4565b50505050565b6000805460408051622f3b1f60e11b8152905162001a1c936001600160a01b0390931692625e763e92600480820193918290030181865afa158015620015e3573d6000803e3d6000fd5b62001a3a5760405163421c007d60e11b815260040160405180910390fd5b600062001a4b60c083018362002e90565b62001a5b916001908290620033a1565b81019062001a6a919062003745565b8051600090815260036020908152604090912054908201519192506001600160a01b03908116911662001ab05760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03811662001ad85760405163c97d95cf60e01b815260040160405180910390fd5b60208201516040516308f2839760e41b81526001600160a01b03918216600482015290821690638f28397090602401600060405180830381600087803b15801562001b2257600080fd5b505af115801562001b37573d6000803e3d6000fd5b505050507f82e0cebbbfcea0d10cf649041c20143e863ed85b7e3427ac67cf58dd502426ee81836020015160405162001b869291906001600160a01b0392831681529116602082015260400190565b60405180910390a1505050565b6000805460408051622f3b1f60e11b8152905162001bdd936001600160a01b0390931692625e763e92600480820193918290030181865afa158015620015e3573d6000803e3d6000fd5b62001bfb5760405163421c007d60e11b815260040160405180910390fd5b600062001c0c60c083018362002e90565b62001c1c916001908290620033a1565b81019062001c2b919062003776565b6020818101805183518051908401206000908152600590935260409283902080546001600160a01b0319166001600160a01b039092169190911790558251905191519293507f8ef5d91f436acad15a0b59c5ac183adcd42a0da26cfaceb0fea4791cccfda31b9262001c9e9290620037de565b60405180910390a15050565b805160005b818110156200044657600083828151811062001ccf5762001ccf62002ee0565b6020908102919091018101516060810151805192810192909220815191935091906001600160a01b03161562001d24578060405160200162001d1291906200380a565b60405160208183030381529060405290505b60208301516001600160a01b031662001e30576000823085604001518460405162001d4f9062002487565b62001d5d9392919062003832565b8190604051809103906000f590508015801562001d7e573d6000803e3d6000fd5b506001600160a01b03808216602087015260a0860151919250161580159062001daa5750608084015115155b1562001e2e5760a084015160808501516040516340c10f1960e01b81526001600160a01b038416926340c10f199262001df9926004016001600160a01b03929092168252602082015260400190565b600060405180830381600087803b15801562001e1457600080fd5b505af115801562001e29573d6000803e3d6000fd5b505050505b505b8251600083815260046020908152604080832080546001600160a01b039586166001600160a01b031991821617909155828801805160039094529382902080549390951692169190911790925584519051828601516060870151608088015160a089015195517f13808dd38566fb55d30620d567d45fb743f01fce0f5f87b5869eb2c7420d97329662001ecc96959493928a9290919062003876565b60405180910390a15050508062001ee39062003729565b905062001caf565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801562001f3d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001f63919062003307565b62001f6f91906200333b565b6040516001600160a01b038516602482015260448101829052909150620019cc90859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152620021b0565b6040516001600160a01b0380851660248301528316604482015260648101829052620019cc9085906323b872dd60e01b9060840162001f9f565b6040516001600160a01b0383166024820152604481018290526200044690849063a9059cbb60e01b9060640162001f9f565b600062002050826200228d565b805190602001209050919050565b60008151835114620020735750600062000372565b825160208381018281209186019283209091145b95945050505050565b60008151601414620020b557604051636616760160e11b815260040160405180910390fd5b506014015190565b6020808201805160009081526004835260408082205492518252600390935291909120546001600160a01b0391821691168115801590620020ff575082604001515b156200211e57620004468262002116856080015190565b855162002011565b6001600160a01b038116156200098157806001600160a01b03166340c10f1962002149856080015190565b855160405160e084901b6001600160e01b03191681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156200219257600080fd5b505af1158015620021a7573d6000803e3d6000fd5b50505050505050565b600062002207826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620022e09092919063ffffffff16565b805190915015620004465780806020019051810190620022289190620038d8565b620004465760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084015b60405180910390fd5b60608160000151826020015183604001518460a00151856060015186608001518760c00151604051602001620022ca9796959493929190620038f8565b6040516020818303038152906040529050919050565b6060620022f18484600085620022fb565b90505b9392505050565b6060824710156200235e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162002284565b600080866001600160a01b031685876040516200237c919062003999565b60006040518083038185875af1925050503d8060008114620023bb576040519150601f19603f3d011682016040523d82523d6000602084013e620023c0565b606091505b5091509150620023d387838387620023e0565b925050505b949350505050565b60608315620024545782516000036200244c576001600160a01b0385163b6200244c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162002284565b5081620023d8565b620023d883838151156200246b5781518083602001fd5b8060405162461bcd60e51b81526004016200228491906200350b565b61148480620039ae83390190565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715620024d057620024d062002495565b60405290565b60405161010081016001600160401b0381118282101715620024d057620024d062002495565b604080519081016001600160401b0381118282101715620024d057620024d062002495565b60405160c081016001600160401b0381118282101715620024d057620024d062002495565b604051602081016001600160401b0381118282101715620024d057620024d062002495565b604051601f8201601f191681016001600160401b038111828210171562002596576200259662002495565b604052919050565b60006001600160401b03821115620025ba57620025ba62002495565b50601f01601f191660200190565b600082601f830112620025da57600080fd5b8135620025f1620025eb826200259e565b6200256b565b8181528460208386010111156200260757600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160401b03811681146200263c57600080fd5b919050565b600060e082840312156200265457600080fd5b6200265e620024ab565b905081356001600160401b03808211156200267857600080fd5b6200268685838601620025c8565b835260208401359150808211156200269d57600080fd5b620026ab85838601620025c8565b6020840152620026be6040850162002624565b60408401526060840135915080821115620026d857600080fd5b620026e685838601620025c8565b606084015260808401359150808211156200270057600080fd5b6200270e85838601620025c8565b60808401526200272160a0850162002624565b60a084015260c08401359150808211156200273b57600080fd5b506200274a84828501620025c8565b60c08301525092915050565b6000606082840312156200276957600080fd5b604051606081016001600160401b0382821081831117156200278f576200278f62002495565b816040528293508435915080821115620027a857600080fd5b620027b68683870162002641565b83526020850135915080821115620027cd57600080fd5b50620027dc85828601620025c8565b602083015250620027f06040840162002624565b60408201525092915050565b6000602082840312156200280f57600080fd5b81356001600160401b038111156200282657600080fd5b6200036e8482850162002756565b600080602083850312156200284857600080fd5b82356001600160401b03808211156200286057600080fd5b818501915085601f8301126200287557600080fd5b8135818111156200288557600080fd5b8660208285010111156200289857600080fd5b60209290920196919550909350505050565b600060208284031215620028bd57600080fd5b81356001600160401b03811115620028d457600080fd5b820160408185031215620022f457600080fd5b6001600160a01b0381168114620028fd57600080fd5b50565b80356200263c81620028e7565b60006001600160401b0382111562002929576200292962002495565b5060051b60200190565b600082601f8301126200294557600080fd5b8135602062002958620025eb836200290d565b82815260059290921b840181019181810190868411156200297857600080fd5b8286015b84811015620029bc5780356001600160401b038111156200299d5760008081fd5b620029ad8986838b0101620025c8565b8452509183019183016200297c565b509695505050505050565b60006101008284031215620029db57600080fd5b620029e5620024d6565b905081356001600160401b0380821115620029ff57600080fd5b62002a0d85838601620025c8565b8352602084013591508082111562002a2457600080fd5b62002a3285838601620025c8565b602084015262002a456040850162002624565b604084015262002a586060850162002900565b606084015262002a6b6080850162002624565b608084015260a084013591508082111562002a8557600080fd5b62002a938583860162002933565b60a084015262002aa660c0850162002624565b60c084015260e084013591508082111562002ac057600080fd5b5062002acf84828501620025c8565b60e08301525092915050565b60006020828403121562002aee57600080fd5b6001600160401b03808335111562002b0557600080fd5b823583016040818603121562002b1a57600080fd5b62002b24620024fc565b828235111562002b3357600080fd5b813582016040818803121562002b4857600080fd5b62002b52620024fc565b848235111562002b6157600080fd5b62002b708883358401620029c7565b8152846020830135111562002b8457600080fd5b60208201358201915087601f83011262002b9d57600080fd5b62002bad620025eb83356200290d565b82358082526020808301929160051b8501018a81111562002bcd57600080fd5b602085015b8181101562002c7857888135111562002bea57600080fd5b803586016040818e03601f1901121562002c0357600080fd5b62002c0d620024fc565b8a6020830135111562002c1f57600080fd5b62002c338e602080850135850101620025c8565b81528a6040830135111562002c4757600080fd5b62002c5c8e60206040850135850101620025c8565b6020820152808652505060208401935060208101905062002bd2565b50508060208401525050808352505062002c956020830162002900565b602082015295945050505050565b60006020828403121562002cb657600080fd5b5035919050565b60006020828403121562002cd057600080fd5b81356001600160401b0381111562002ce757600080fd5b820160608185031215620022f457600080fd5b60006020828403121562002d0d57600080fd5b81356001600160401b0381111562002d2457600080fd5b82016101208185031215620022f457600080fd5b60006020828403121562002d4b57600080fd5b81356001600160401b038082111562002d6357600080fd5b908301906040828603121562002d7857600080fd5b62002d82620024fc565b82358281111562002d9257600080fd5b62002da08782860162002756565b8252506020830135925062002db583620028e7565b6020810192909252509392505050565b60006020828403121562002dd857600080fd5b81356001600160401b0381111562002def57600080fd5b820160e08185031215620022f457600080fd5b6040810162000372828480516001600160a01b03908116835260209182015116910152565b60006020828403121562002e3a57600080fd5b81356001600160401b0381111562002e5157600080fd5b6200036e84828501620029c7565b8183823760009101908152919050565b6000823560de1983360301811262002e8657600080fd5b9190910192915050565b6000808335601e1984360301811262002ea857600080fd5b8301803591506001600160401b0382111562002ec357600080fd5b60200191503681900382131562002ed957600080fd5b9250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b80546001600160a01b0319166001600160a01b0392909216919091179055565b813562002f3981620028e7565b62002f45818362002f0c565b50602082013562002f5681620028e7565b62000446816001840162002f0c565b6000808335601e1984360301811262002f7d57600080fd5b8301803591506001600160401b0382111562002f9857600080fd5b6020019150600581901b360382131562002ed957600080fd5b600060c0828403121562002fc457600080fd5b62002fce62002521565b905062002fdb8262002900565b815262002feb6020830162002900565b602082015260408201356001600160401b03808211156200300b57600080fd5b6200301985838601620025c8565b604084015260608401359150808211156200303357600080fd5b506200304284828501620025c8565b606083015250608082013560808201526200306060a0830162002900565b60a082015292915050565b60006200307c620025eb846200290d565b80848252602080830192508560051b8501368111156200309b57600080fd5b855b81811015620030db5780356001600160401b03811115620030be5760008081fd5b620030cc36828a0162002fb1565b8652509382019382016200309d565b50919695505050505050565b600060208284031215620030fa57600080fd5b8151620022f481620028e7565b6000602082840312156200311a57600080fd5b8135620022f481620028e7565b8015158114620028fd57600080fd5b6000602082840312156200314957600080fd5b8135620022f48162003127565b634e487b7160e01b600052601160045260246000fd5b8181038181111562000372576200037262003156565b60005b838110156200319f57818101518382015260200162003185565b50506000910152565b60008151808452620031c281602086016020860162003182565b601f01601f19169290920160200192915050565b60208152815160208201526020820151604082015260408201511515606082015260608201516080820152608082015160a0820152600060a083015160c0808401526200036e60e0840182620031a8565b60008152600082516200324281600185016020870162003182565b9190910160010192915050565b6000602082840312156200326257600080fd5b620022f48262002624565b602081526000825160c060208401526200328b60e0840182620031a8565b90506020840151601f1980858403016040860152620032ab8383620031a8565b9250604086015191508085840301606086015250620032cb8282620031a8565b9150506001600160401b036060850151166080840152608084015160a084015260018060a01b0360a08501511660c08401528091505092915050565b6000602082840312156200331a57600080fd5b5051919050565b808202811582820484141762000372576200037262003156565b8082018082111562000372576200037262003156565b86815260a060208201528460a0820152848660c0830137600060c08683010152600060c0601f19601f88011683010190508460408301528360608301528215156080830152979650505050505050565b60008085851115620033b257600080fd5b83861115620033c057600080fd5b5050820193919092039150565b600060208284031215620033e057600080fd5b81356001600160401b0380821115620033f857600080fd5b9083019060c082860312156200340d57600080fd5b6200341762002521565b82358152602083013560208201526040830135620034358162003127565b80604083015250606083013560608201526080830135608082015260a0830135828111156200346357600080fd5b6200347187828601620025c8565b60a08301525095945050505050565b600060a082840312156200349357600080fd5b60405160a081018181106001600160401b0382111715620034b857620034b862002495565b806040525082358152602083013560208201526040830135620034db8162003127565b6040820152606083810135908201526080928301359281019290925250919050565b600062000372368362002641565b602081526000620022f46020830184620031a8565b6000602082840312156200353357600080fd5b81516001600160401b038111156200354a57600080fd5b8201601f810184136200355c57600080fd5b80516200356d620025eb826200259e565b8181528560208385010111156200358357600080fd5b6200208782602083016020860162003182565b600060408284031215620035a957600080fd5b620035b3620024fc565b8235620035c081620028e7565b81526020830135620035d281620028e7565b60208201529392505050565b82546001600160a01b039081168252600184015416602082015260808101620022f4604083018480516001600160a01b03908116835260209182015116910152565b6000602082840312156200363357600080fd5b81356001600160401b038111156200364a57600080fd5b6200036e8482850162002fb1565b600060208083850312156200366c57600080fd5b82356001600160401b03808211156200368457600080fd5b81850191508282870312156200369957600080fd5b620036a362002546565b823582811115620036b357600080fd5b80840193505086601f840112620036c957600080fd5b82359150620036dc620025eb836200290d565b82815260059290921b83018401918481019088841115620036fc57600080fd5b938501935b838510156200371c5784358252938501939085019062003701565b8252509695505050505050565b6000600182016200373e576200373e62003156565b5060010190565b6000604082840312156200375857600080fd5b62003762620024fc565b823581526020830135620035d281620028e7565b6000602082840312156200378957600080fd5b81356001600160401b0380821115620037a157600080fd5b9083019060408286031215620037b657600080fd5b620037c0620024fc565b823582811115620037d057600080fd5b62002da087828601620025c8565b604081526000620037f36040830185620031a8565b905060018060a01b03831660208301529392505050565b600082516200381e81846020870162003182565b6105cd60f31b920191825250600201919050565b6001600160a01b03841681526060602082018190526000906200385890830185620031a8565b82810360408401526200386c8185620031a8565b9695505050505050565b600060018060a01b03808a168352808916602084015260e06040840152620038a260e0840189620031a8565b8381036060850152620038b68189620031a8565b60808501979097525060a083019490945250911660c090910152949350505050565b600060208284031215620038eb57600080fd5b8151620022f48162003127565b600088516200390c818460208d0162003182565b88519083019062003922818360208d0162003182565b60c089811b6001600160c01b03199081169390920192835288901b166008820152855162003958816010840160208a0162003182565b85519101906200397081601084016020890162003182565b84519101906200398881601084016020880162003182565b016010019998505050505050505050565b6000825162002e868184602087016200318256fe60806040523480156200001157600080fd5b5060405162001484380380620014848339810160408190526200003491620002b3565b81816004620000448382620003cc565b506005620000538282620003cc565b506200006a915063b6ba5da360e01b90506200016a565b6200007c63dd0390b560e01b6200016a565b6200008e637248fa3360e11b6200016a565b50506001600160a01b031660009081527f15e730a082bd931bd9f1fc81c9aa2c9308a74dbdf27de2bec5058a0e60fe64aa602090815260408083208054600160ff1991821681179092557fc9597e0dd7b45d7b4c627952a921a5050cad933a06ad3e737ecde71f09857812845282852080548216831790557f4e686283402f72de62620fd26e24e5a6c7bd1d6067c734dda678ed6e18ad6ab3845282852080548216831790557f30a921b2188042103ab7d696490f6fa125548bb0385c7319673533fb2dce7e5b90935292208054909116909117905562000498565b6001600160e01b03198082169003620001c95760405162461bcd60e51b815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015260640160405180910390fd5b6001600160e01b0319166000908152602081905260409020805460ff19166001179055565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200021657600080fd5b81516001600160401b0380821115620002335762000233620001ee565b604051601f8301601f19908116603f011681019082821181831017156200025e576200025e620001ee565b816040528381526020925086838588010111156200027b57600080fd5b600091505b838210156200029f578582018301518183018401529082019062000280565b600093810190920192909252949350505050565b600080600060608486031215620002c957600080fd5b83516001600160a01b0381168114620002e157600080fd5b60208501519093506001600160401b0380821115620002ff57600080fd5b6200030d8783880162000204565b935060408601519150808211156200032457600080fd5b50620003338682870162000204565b9150509250925092565b600181811c908216806200035257607f821691505b6020821081036200037357634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003c757600081815260208120601f850160051c81016020861015620003a25750805b601f850160051c820191505b81811015620003c357828155600101620003ae565b5050505b505050565b81516001600160401b03811115620003e857620003e8620001ee565b6200040081620003f984546200033d565b8462000379565b602080601f8311600181146200043857600084156200041f5750858301515b600019600386901b1c1916600185901b178555620003c3565b600085815260208120601f198616915b82811015620004695788860151825594840194600190910190840162000448565b5085821015620004885787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b610fdc80620004a86000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c80638f283970116100b8578063a9059cbb1161007c578063a9059cbb146102d0578063c5b66dc9146102e3578063d539139314610309578063d547741f14610330578063dd62ed3e14610343578063ea35f36c1461035657600080fd5b80638f2839701461025657806391d148541461026957806395d89b41146102a25780639dc29fac146102aa578063a457c2d7146102bd57600080fd5b8063282c51f31161010a578063282c51f3146101bc5780632f2ff15d146101e3578063313ce567146101f8578063395093511461020757806340c10f191461021a57806370a082311461022d57600080fd5b806301ffc9a71461014757806306fdde031461016f578063095ea7b31461018457806318160ddd1461019757806323b872dd146101a9575b600080fd5b61015a610155366004610d99565b61037c565b60405190151581526020015b60405180910390f35b61017761038d565b6040516101669190610dca565b61015a610192366004610e34565b61041f565b6003545b604051908152602001610166565b61015a6101b7366004610e5e565b610437565b61019b7fe7ba54b021ea26ee9c797c92a7485e5bb59d2b07365aae349635a1bf8d0bd7af81565b6101f66101f1366004610e9a565b61045b565b005b60405160128152602001610166565b61015a610215366004610e34565b6104c5565b6101f6610228366004610e34565b6104e7565b61019b61023b366004610ec6565b6001600160a01b031660009081526001602052604090205490565b6101f6610264366004610ec6565b610567565b61015a610277366004610e9a565b60009182526006602090815260408084206001600160a01b0393909316845291905290205460ff1690565b61017761067b565b6101f66102b8366004610e34565b61068a565b61015a6102cb366004610e34565b610706565b61015a6102de366004610e34565b610786565b7fe7ba54b021ea26ee9c797c92a7485e5bb59d2b07365aae349635a1bf8d0bd7af61019b565b61019b7f71c3f5d1e4abab6db588a0fd893947888ebf8abda567a125ca9d5845ef22dda581565b6101f661033e366004610e9a565b610794565b61019b610351366004610ee1565b6107fb565b7f71c3f5d1e4abab6db588a0fd893947888ebf8abda567a125ca9d5845ef22dda561019b565b600061038782610826565b92915050565b60606004805461039c90610f0b565b80601f01602080910402602001604051908101604052809291908181526020018280546103c890610f0b565b80156104155780601f106103ea57610100808354040283529160200191610415565b820191906000526020600020905b8154815290600101906020018083116103f857829003601f168201915b5050505050905090565b60003361042d818585610862565b5060019392505050565b600033610445858285610987565b610450858585610a01565b506001949350505050565b600082815260076020908152604080832033845290915290205460ff166104955760405163521128ff60e01b815260040160405180910390fd5b60009182526006602090815260408084206001600160a01b0390931684529190529020805460ff19166001179055565b60003361042d8185856104d883836107fb565b6104e29190610f45565b610862565b336000908152600080516020610f67833981519152602052604090205460ff1615801561053b57506105397f71c3f5d1e4abab6db588a0fd893947888ebf8abda567a125ca9d5845ef22dda533610277565b155b1561055957604051630782484160e21b815260040160405180910390fd5b6105638282610bac565b5050565b336000908152600080516020610f67833981519152602052604090205460ff1615806105b05750336000908152600080516020610f87833981519152602052604090205460ff16155b156105ce5760405163521128ff60e01b815260040160405180910390fd5b336000908152600080516020610f6783398151915260209081526040808320805460ff19908116909155600080516020610f87833981519152909252909120805490911690556001600160a01b0381166106255750565b6001600160a01b03166000908152600080516020610f67833981519152602090815260408083208054600160ff199182168117909255600080516020610f87833981519152909352922080549091169091179055565b60606005805461039c90610f0b565b336000908152600080516020610f87833981519152602052604090205460ff161580156106de57506106dc7fe7ba54b021ea26ee9c797c92a7485e5bb59d2b07365aae349635a1bf8d0bd7af33610277565b155b156106fc57604051630782484160e21b815260040160405180910390fd5b6105638282610c6d565b6000338161071482866107fb565b9050838110156107795760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6104508286868403610862565b60003361042d818585610a01565b600082815260076020908152604080832033845290915290205460ff166107ce5760405163521128ff60e01b815260040160405180910390fd5b60009182526006602090815260408084206001600160a01b0390931684529190529020805460ff19169055565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b60006301ffc9a760e01b6001600160e01b0319831614806103875750506001600160e01b03191660009081526020819052604090205460ff1690565b6001600160a01b0383166108c45760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610770565b6001600160a01b0382166109255760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610770565b6001600160a01b0383811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b600061099384846107fb565b905060001981146109fb57818110156109ee5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610770565b6109fb8484848403610862565b50505050565b6001600160a01b038316610a655760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610770565b6001600160a01b038216610ac75760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610770565b6001600160a01b03831660009081526001602052604090205481811015610b3f5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610770565b6001600160a01b0380851660008181526001602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610b9f9086815260200190565b60405180910390a36109fb565b6001600160a01b038216610c025760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610770565b8060036000828254610c149190610f45565b90915550506001600160a01b0382166000818152600160209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b038216610ccd5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610770565b6001600160a01b03821660009081526001602052604090205481811015610d415760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610770565b6001600160a01b03831660008181526001602090815260408083208686039055600380548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910161097a565b600060208284031215610dab57600080fd5b81356001600160e01b031981168114610dc357600080fd5b9392505050565b600060208083528351808285015260005b81811015610df757858101830151858201604001528201610ddb565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b0381168114610e2f57600080fd5b919050565b60008060408385031215610e4757600080fd5b610e5083610e18565b946020939093013593505050565b600080600060608486031215610e7357600080fd5b610e7c84610e18565b9250610e8a60208501610e18565b9150604084013590509250925092565b60008060408385031215610ead57600080fd5b82359150610ebd60208401610e18565b90509250929050565b600060208284031215610ed857600080fd5b610dc382610e18565b60008060408385031215610ef457600080fd5b610efd83610e18565b9150610ebd60208401610e18565b600181811c90821680610f1f57607f821691505b602082108103610f3f57634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561038757634e487b7160e01b600052601160045260246000fdfe15e730a082bd931bd9f1fc81c9aa2c9308a74dbdf27de2bec5058a0e60fe64aac9597e0dd7b45d7b4c627952a921a5050cad933a06ad3e737ecde71f09857812a264697066735822122096925c25124dd453b381a457f60ce16902311e20a61a7463a6fa80841b7f653764736f6c63430008110033a26469706673582212209bd14071144e283355300217ee5f2658ab8edcbb2a54176356f5f6d22c1b81f364736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a6ab534d799e30fb71e4f9b0cf768bb49ff9fa64
-----Decoded View---------------
Arg [0] : admin (address): 0xA6aB534d799e30Fb71E4F9b0CF768bB49ff9fa64
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000a6ab534d799e30fb71e4f9b0cf768bb49ff9fa64
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.