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
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Teleport | 18378698 | 399 days ago | IN | 0 ETH | 0.000000074678 | ||||
| Teleport | 18284756 | 401 days ago | IN | 0 ETH | 0.000000218097 | ||||
| Teleport | 18247421 | 402 days ago | IN | 0 ETH | 0.00000250077 | ||||
| Teleport | 18246447 | 402 days ago | IN | 0 ETH | 0.000003140526 | ||||
| Teleport | 18182947 | 403 days ago | IN | 0 ETH | 0.000004513093 | ||||
| Teleport | 18182644 | 403 days ago | IN | 0 ETH | 0.000005055038 | ||||
| Teleport | 18095196 | 405 days ago | IN | 0 ETH | 0.000002375783 | ||||
| Teleport | 18081992 | 405 days ago | IN | 0 ETH | 0.000010181844 | ||||
| Teleport | 18010645 | 407 days ago | IN | 0 ETH | 0.000003047195 | ||||
| Teleport | 18010582 | 407 days ago | IN | 0 ETH | 0.000003201147 | ||||
| Teleport | 18010473 | 407 days ago | IN | 0 ETH | 0.000002593224 | ||||
| Teleport | 17765803 | 413 days ago | IN | 0 ETH | 0.000007718017 | ||||
| Teleport | 17381760 | 422 days ago | IN | 0.05 ETH | 0.00002380809 | ||||
| Teleport | 17381727 | 422 days ago | IN | 0.05 ETH | 0.000026703933 | ||||
| Teleport | 17381663 | 422 days ago | IN | 0.01 ETH | 0.000023670169 | ||||
| Teleport | 17381643 | 422 days ago | IN | 0.001 ETH | 0.000024622226 | ||||
| Teleport | 17362395 | 422 days ago | IN | 0.000001 ETH | 0.000023115743 | ||||
| Init | 17225838 | 425 days ago | IN | 0 ETH | 0.000409164638 |
Latest 2 internal transactions
| Parent Transaction Hash | Block | From | To | Amount | ||
|---|---|---|---|---|---|---|
| 17359702 | 422 days ago | Contract Creation | 0 ETH | |||
| 17225838 | 425 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": {}
}Contract ABI
API[{"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
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.