false
false
0

Contract Address Details

0x3406A50e4c09588C5228A59fA4613531b7091e80

Contract Name
BridgeV2
Creator
0xef1174–c071f8 at 0x394a1b–50983e
Balance
0 CLO
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
18618091
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
BridgeV2




Optimization enabled
true
Compiler version
v0.8.19+commit.7dd6d404




Optimization runs
200
EVM Version
default




Verified at
2025-03-13T18:58:03.548901Z

contracts/BridgeV2.sol

// SPDX-License-Identifier: No License (None)
pragma solidity ^0.8.0;

interface IERC20TokenCloned {
    // initialize cloned token just for ERC20TokenCloned
    function initialize(
        string calldata name,
        string calldata symbol,
        uint8 decimals
    ) external;

    function mint(address user, uint256 amount) external;
    function burnFrom(address account, uint256 amount) external returns (bool);
    function burn(uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
    function allowance(address _owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function decimals() external view returns (uint8);
    function symbol() external view returns (string memory);
    function name() external view returns (string memory);
    function transferOwnership(address newOwner) external;
}

interface IContractCaller {
    function callContract(
        address user,
        address token,
        uint256 value,
        address toContract,
        bytes memory data
    ) external payable;
}

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library Clones {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create(0, ptr, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create2(0, ptr, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
            mstore(add(ptr, 0x38), shl(0x60, deployer))
            mstore(add(ptr, 0x4c), salt)
            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
            predicted := keccak256(add(ptr, 0x37), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(address implementation, bytes32 salt)
        internal
        view
        returns (address predicted)
    {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    function safeApprove(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
    }

    function safeTransfer(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
    }

    function safeTransferFrom(address token, address from, address to, uint value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
    }

    function safeTransferETH(address to, uint value) internal {
        (bool success,) = to.call{value:value}(new bytes(0));
        require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
    }
}

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256`
 * (`UintSet`) are supported.
 */
library EnumerableSet {
    struct AddressSet {
        // Storage of set values
        address[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(address => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value)
        internal
        returns (bool)
    {
        if (!contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value)
        internal
        returns (bool)
    {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            address lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value)
        internal
        view
        returns (bool)
    {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns 1-based index of value in the set. O(1).
     */
    function indexOf(AddressSet storage set, address value)
        internal
        view
        returns (uint256)
    {
        return set._indexes[value];
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index)
        internal
        view
        returns (address)
    {
        require(
            set._values.length > index,
            "EnumerableSet: index out of bounds"
        );
        return set._values[index];
    }
}

abstract contract Ownable {
    address internal _owner;

    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    /* will use initialize instead
    constructor () {
        _owner = msg.sender;
        emit OwnershipTransferred(address(0), msg.sender);
    }
    */
    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == msg.sender, "Ownable: caller is not the owner");
        _;
    }

}

interface IBridge {
    function owner() external view returns (address);
}

contract ContractCaller {
    using TransferHelper for address;
    address constant NATIVE_COINS = address(1); // address is considered as native coins 
    address public bridge;

    event RescuedTokens(address token, address to, uint256 balance);

    modifier onlyOwner() {
        require(msg.sender == IBridge(bridge).owner(), "Only owner"); // owner multisig
        _;
    }

    modifier onlyBridge() {
        require(msg.sender == bridge, "Only bridge"); // Bridge contract address
        _;
    }

    constructor () {
        bridge = msg.sender;
    }

    function tokenReceived(address _from, uint, bytes calldata) external view{
        require(_from == bridge, "Only from bridge"); // Bridge contract address
    }
    
    function rescueTokens(address token, address to) external onlyOwner {
        uint256 balance;
        if (token == address(0)) {
            balance = address(this).balance;
            to.safeTransferETH(balance);
        } else {
            balance = IERC20TokenCloned(token).balanceOf(address(this));
            token.safeTransfer(to, balance);
        }
        emit RescuedTokens(token, to, balance);
    }

    function callContract(address user, address token, uint256 value, address toContract, bytes memory data) external payable onlyBridge {
        if (token == NATIVE_COINS) {
            value = msg.value;
            uint balanceBefore = address(this).balance - value; // balance before
            (bool success,) = toContract.call{value: value}(data);
            if (success) value = address(this).balance - balanceBefore; // check, if we have some rest of token
            if (value != 0) user.safeTransferETH(value);  // send coin to user
        } else {
            token.safeApprove(toContract, value);
            (bool success,) = toContract.call{value: 0}(data);
            if (success) value = IERC20TokenCloned(token).allowance(address(this), toContract); // unused amount (the rest) = allowance
            if (value != 0) {   // if not all value used reset approvement
                token.safeApprove(toContract, 0);
                token.safeTransfer(user, value);   // send to user rest of tokens
            }                
        }
    }
}

contract BridgeV2 is Ownable {
    using TransferHelper for address;
    using EnumerableSet for EnumerableSet.AddressSet;
    EnumerableSet.AddressSet authorities; // authority has to sign claim transaction (message)
    EnumerableSet.AddressSet tokenList; // list of added tokens in the bridge on this chain
    address constant NATIVE_COINS = address(1); // address is considered as native coins

    struct Token {
        address token; // origin token address
        uint256 chainID; // origin token chainID
        address wrappedToken; // address of wrapped token on this chain (address(0) if no wrapped token)
        address authority; // authority address that MUST approve token transfer. address(0) - not set. It may not be in the authorities list
    }

    struct Upgrade {
        address newContract;
        uint64 validFrom;
    }

    // Token details for frontend returns by getTokenList function
    struct TokenDetails {
        address token;
        uint8 decimals;
        string name;
        string symbol;
    }

    uint256 public threshold; // minimum number of signatures required to approve swap
    address public tokenImplementation; // implementation of wrapped token
    address public feeTo; // send fee to this address
    bool public frozen; // if frozen - swap will not work
    mapping(uint256 => mapping(bytes32 => bool)) public isTxProcessed;    // chainID => txID => isProcessed
    mapping(address => uint256) public tokenDeposits; // amount of tokens were deposited by users
    mapping(address => bool) public isFreezer; // addresses that have right to freeze contract
    uint256 public setupMode; // time when setup mode will start, 0 if disable
    Upgrade public upgradeData; // data for upgrade to new contract
    address public founders;    // founders multisig wallet. It has right to change owner
    address public contractCaller; // intermediate contract that calls third-party contract functions (toContract)
    
    mapping(bytes32 => Token) internal addedTokens; // native (wrapped) token address => Token struct
    mapping(address => bytes32) internal nativeToToken; // mapping from native token to key hash for Token structure
    mapping(uint256 => bool) public isSupported; // chainID => isSupported
    mapping(address => bool) public requiredAuthorities; // authority address that MUST sign swap transaction (trusted authorities)
    uint256 public minRequiredAuthorities; // minimum number of trusted authorities required to sign transaction
    mapping(address nativeToken => uint256) internal bridgeFee; // fee in percent with 4 decimals (i.e. 1.5% = 15000) for specific token. 0 - no fee. bridgeFee[address(0)] - global fee

    event SetAuthority(address authority, bool isEnable);
    event SetRequiredAuthority(address authority, bool isEnable);
    event SetTokenAuthority(address indexed token, uint256 chainId, address authority);
    event SetFeeTo(address previousFeeTo, address newFeeTo);
    event SetBridgeFee(address token, uint256 fee); // fee in percent with 4 decimals (i.e. 1.5% = 15000). 0 - no fee. bridgeFee[address(0)] - global fee
    event SetThreshold(uint256 threshold);
    event SetContractCaller(address newContractCaller);
    event Deposit(
        address indexed originalToken,
        uint256 originalChainID,
        address indexed token,
        address indexed receiver,
        uint256 value,
        uint256 toChainId
    );
    event Claim(
        address indexed originalToken,
        uint256 originalChainID,
        address indexed token,
        address indexed to,
        uint256 value,
        bytes32 txId,
        uint256 fromChainId
    );
    event Fee(address sender, address token, uint256 fee); // fee amount in token paid by user.
    event CreatePair(address toToken, address fromToken, uint256 fromChainId);
    event Frozen(bool status);
    event RescuedERC20(address token, address to, uint256 value);
    event SetFreezer(address freezer, bool isActive);
    event SetupMode(uint256 time);
    event UpgradeRequest(address newContract, uint256 validFrom);
    event BridgeToContract(
        address indexed originalToken,
        uint256 originalChainID,
        address indexed token,
        address indexed receiver,
        uint256 value,
        uint256 toChainId,
        address toContract,
        bytes data
    );
    event ClaimToContract(
        address indexed originalToken,
        uint256 originalChainID,
        address indexed token,
        address indexed to,
        uint256 value,
        bytes32 txId,
        uint256 fromChainId,
        address toContract
    );
    event AddToken(
        address indexed token,
        uint256 chainID,
        uint256 decimals,
        string name,
        string symbol
    );
    event SetSupportedChain(uint256 chainID, bool isSupported);

    // run only once from proxy
    function initialize(
        address newOwner,   // bridge owner (company wallet)
        address newFounders,
        address _feeTo,    // wallet which receive fees from bridge
        address _tokenImplementation,   // token implementation contract
        //address _contractCaller,        // intermediate contract caller
        uint256 _threshold,             // minimum authorities required to approve bridge transaction
        address[] calldata _authorities, // addresses of authorities. _authorities[0] is requiredAuthority
        string calldata _nativeCoin     // name of native coin (i.e. ETH, BNB, MATIC)
    ) external {
        require(
            newOwner != address(0) &&
            newFounders != address(0) &&
            _owner == address(0) &&
            _feeTo != address(0)
        ); // run only once
        _owner = newOwner;
        founders = newFounders;
        emit OwnershipTransferred(address(0), newOwner);
        require(
            _tokenImplementation != address(0),
            "Wrong tokenImplementation"
        );
        require(
            _threshold != 0,
            "Wrong threshold"
        );
        require(
            authorities.length() + _authorities.length < 255, 
            "Too many authorities"
        );
        for (uint256 i = 0; i < _authorities.length; i++){
            require(_authorities[i] != address(0), "Zero address");
            require(authorities.add(_authorities[i]), "Authority already added");
            emit SetAuthority(_authorities[i], true);
        }        
        tokenImplementation = _tokenImplementation;
        //contractCaller = _contractCaller;
        contractCaller = address(new ContractCaller());
        //emit SetContractCaller(_contractCaller);
        feeTo = _feeTo;
        emit SetFeeTo(address(0), _feeTo);
        threshold = _threshold;
        emit SetThreshold(_threshold);
        requiredAuthorities[_authorities[0]] = true;
        emit SetRequiredAuthority(_authorities[0], true);
        minRequiredAuthorities = 1;
        setupMode = 1; // allow setup after deployment
        // add native coin to bridge
        bytes32 key = keccak256(abi.encodePacked(address(1), block.chainid));
        addedTokens[key].token = address(1);
        addedTokens[key].chainID = block.chainid;
        nativeToToken[address(1)] = key;
        emit AddToken(address(1), block.chainid, 18, _nativeCoin, _nativeCoin);
    }

    constructor () {
        _owner = address(1);    // disallow to use implementation contract directly
    }
    modifier notFrozen() {
        require(!frozen, "Bridge is frozen");
        _;
    }

    // allowed only in setup mode
    modifier onlySetup() {
        uint256 mode = setupMode; //use local variable to save gas
        require(mode != 0 && mode < block.timestamp, "Not in setup mode");
        _;
    }

    function upgradeTo() external view returns (address newContract) {
        Upgrade memory upg = upgradeData;
        require(
            upg.validFrom < block.timestamp && upg.newContract != address(0),
            "Upgrade not allowed"
        );
        newContract = upg.newContract;
    }

    function requestUpgrade(address newContract) external onlyOwner {
        require(newContract != address(0), "Zero address");
        uint256 validFrom = block.timestamp;// + 3 days; // remove delay for testing
        upgradeData = Upgrade(newContract, uint64(validFrom));
        emit UpgradeRequest(newContract, validFrom);
    }
    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */

    function transferOwnership(address newOwner) public {
        require(founders == msg.sender || _owner == msg.sender, "Ownable: caller is not the founders");
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }

    function changeFounder(address newFounders) public {
        require(founders == msg.sender, "caller is not the founders");
        require(newFounders != address(0), "new owner is the zero address");
        emit OwnershipTransferred(founders, newFounders);
        founders = newFounders;
    }

    // get number of authorities
    function getAuthoritiesNumber() external view returns (uint256) {
        return authorities.length();
    }

    // returns list of authorities addresses
    function getAuthorities() external view returns (address[] memory) {
        return authorities._values;
    }

    // Owner or Authority may freeze bridge in case of anomaly detection
    function freeze() external {
        require(
            msg.sender == owner() ||
                authorities.contains(msg.sender) ||
                isFreezer[msg.sender]
        );
        frozen = true;
        emit Frozen(true);
    }

    // Only owner can manually unfreeze contract
    function unfreeze() external onlyOwner onlySetup {
        frozen = false;
        emit Frozen(false);
    }

    // add address to freezer list (who can freeze bridge)
    function setFreezer(address freezer, bool isActive) external onlyOwner {
        require(freezer != address(0), "Zero address");
        isFreezer[freezer] = isActive;
        emit SetFreezer(freezer, isActive);
    }

    // add authorities
    function addAuthorities(address[] calldata _authorities) external onlyOwner onlySetup {
        require(authorities.length() + _authorities.length < 255, "Too many authorities");
        for (uint256 i = 0; i < _authorities.length; i++){
            require(_authorities[i] != address(0), "Zero address");
            require(authorities.add(_authorities[i]), "Authority already added");
            emit SetAuthority(_authorities[i], true);
        }
    }

    // remove authorities
    function removeAuthorities(address[] calldata _authorities) external onlyOwner {
        for (uint256 i = 0; i < _authorities.length; i++){
            require(authorities.remove(_authorities[i]), "Authority does not exist");
            emit SetAuthority(_authorities[i], false);
        }
    }

    // set authority address that MUST sign claim request
    function setRequiredAuthorities(address[] calldata _authorities, bool isActive)
        external
        onlyOwner
        onlySetup
    {
        for (uint256 i = 0; i < _authorities.length; i++){
            requiredAuthorities[_authorities[i]] = isActive;
            emit SetRequiredAuthority(_authorities[i], isActive);
        }
    }

    // get fee for specific token, if fee is not set, return global fee
    function getBridgeFee(address token) public view returns (uint256 fee) {
        fee = bridgeFee[token];
        if (fee == 0) fee = bridgeFee[address(0)];  // return global fee
        else if (fee == 100000) fee = 0; // if fee == 100000, it means 0 fee for specific token
    }

    // fee percent with 4 decimals (i.e. 1.5% = 15000) that will subtracted from deposited tokens. 0 - no fee. bridgeFee[address(0)] - global fee
    function setBridgeFee(address token, uint256 fee) external onlyOwner onlySetup {
        require(fee <= 100000, "Too high fee"); // fee must be less than 10% (99999 max). If fee == 100000, it will set 0 fee for specific token
        bridgeFee[token] = fee;
        emit SetBridgeFee(token, fee);
    }

    // set fee receiver address
    function setFeeTo(address newFeeTo) external onlyOwner onlySetup {
        require(newFeeTo != address(0), "Zero address");
        address previousFeeTo = feeTo;
        feeTo = newFeeTo;
        emit SetFeeTo(previousFeeTo, newFeeTo);
    }

    // set threshold - minimum number of signatures required to approve swap
    function setThreshold(uint256 _threshold, uint256 _minRequiredAuthorities) external onlyOwner onlySetup {
        require(
            _threshold != 0 && _threshold <= authorities.length() && _minRequiredAuthorities <= _threshold,
            "Wrong threshold"
        );
        minRequiredAuthorities = _minRequiredAuthorities;
        threshold = _threshold;
        emit SetThreshold(_threshold);
    }

    // set contractCaller address
    function setContractCaller(address newContractCaller)
        external
        onlyOwner
        onlySetup
    {
        contractCaller = newContractCaller;
        emit SetContractCaller(newContractCaller);
    }

    // set supported chain
    function setSupportedChain(uint256[] calldata _chainID, bool _isSupported)
        external
        onlyOwner
        onlySetup
    {
        for (uint256 i = 0; i < _chainID.length; i++){
            isSupported[_chainID[i]] = _isSupported;
            emit SetSupportedChain(_chainID[i], _isSupported);
        }
    }

    function disableSetupMode() external onlyOwner {
        setupMode = 0;
        emit SetupMode(0);
    }

    function enableSetupMode() external onlyOwner {
        setupMode = block.timestamp + 1 days;
        emit SetupMode(setupMode);
    }

    function rescueERC20(address token, address to) external onlyOwner {
        uint256 value = IERC20TokenCloned(token).balanceOf(address(this)) -
            tokenDeposits[token];
        token.safeTransfer(to, value);
        emit RescuedERC20(token, to, value);
    }

    // return Token structure for selected original token address and chainID
    function getToken(address originalToken, uint256 originalChainID)
        external
        view
        returns (Token memory)
    {
        return
            addedTokens[
                keccak256(abi.encodePacked(originalToken, originalChainID))
            ];
    }

    // return Token structure for native token address (token from native chain)
    function getToken(address nativeToken)
        external
        view
        returns (Token memory)
    {
        bytes32 key = nativeToToken[nativeToken];
        return addedTokens[key];
    }

    // return list of added tokens
    function getTokenList() external view returns (TokenDetails[] memory) {
        uint len = tokenList.length();
        TokenDetails[] memory tokens = new TokenDetails[](len);
        for (uint i = 0; i < len; i++){
            address token = tokenList.at(i);
            //bytes32 key = nativeToToken[token];
            tokens[i] = TokenDetails(
                token,
                IERC20TokenCloned(token).decimals(),
                IERC20TokenCloned(token).name(),
                IERC20TokenCloned(token).symbol()
            );
        }
        return tokens;
    }

    // add new token to the bridge
    function addToken(address token) external {
        require(uint256(nativeToToken[token]) == 0, "Token already added");
        string memory name = IERC20TokenCloned(token).name();
        string memory symbol = IERC20TokenCloned(token).symbol();
        uint256 decimals = IERC20TokenCloned(token).decimals();
        bytes32 key = keccak256(abi.encodePacked(token, block.chainid));
        addedTokens[key].token = token;
        addedTokens[key].chainID = block.chainid;
        addedTokens[key].wrappedToken = address(0);
        nativeToToken[token] = key;
        tokenList.add(token);
        emit AddToken(token, block.chainid, decimals, name, symbol);
    }

    // add wrapped token 
    function addWrappedToken(
        address token, // original token address
        uint256 chainID, // original token chain ID
        uint256 decimals, // original token decimals
        string calldata name, // original token name
        string calldata symbol, // original token symbol
        bytes[] memory sig // authority signatures
    ) external {
        require(chainID != block.chainid, "Only foreign token");
        bytes32 key = keccak256(abi.encodePacked(token, chainID));
        require(addedTokens[key].token == address(0), "Token already added");
        bytes32 messageHash = keccak256(
            abi.encodePacked(token, chainID, decimals, name, symbol)
        );
        checkSignatures(address(0), messageHash, sig);
        string memory _name = string(abi.encodePacked("Wrapped ", name));
        string memory _symbol = string(abi.encodePacked("W", symbol));
        address wrappedToken = Clones.cloneDeterministic(
            tokenImplementation,
            bytes32(uint256(uint160(token)))
        );
        IERC20TokenCloned(wrappedToken).initialize(
            _name,
            _symbol,
            uint8(decimals)
        );
        addedTokens[key].token = token;
        addedTokens[key].chainID = chainID;
        addedTokens[key].wrappedToken = wrappedToken;
        nativeToToken[wrappedToken] = key;
        tokenList.add(wrappedToken);
        emit CreatePair(wrappedToken, token, chainID); //wrappedToken - wrapped token contract address
    }

    // set MUST authority for specific token
    function setTokenMustAuthority(
        address token, // original token address
        uint256 chainID, // original token chain ID
        address authority // address of MUST authority for this token, address(0) if don't need specific authority
    ) external onlyOwner {
        bytes32 key = keccak256(abi.encodePacked(token, chainID));
        require(addedTokens[key].token != address(0), "token not exist");
        require(addedTokens[key].authority != address(0), "change authority not allowed");
        require(authority != address(0));
        addedTokens[key].authority = authority;
        emit SetTokenAuthority(token, chainID, authority);
    }

    // Move tokens through the bridge and call the contract with 'data' parameters on the destination chain
    function bridgeToContract(
        address receiver, // address of token receiver on destination chain
        address token, // token that user send (if token address < 32, then send native coin)
        uint256 value, // tokens value
        uint256 toChainId, // destination chain Id where will be claimed tokens
        address toContract, // this contract will be called on destination chain
        bytes memory data // this data will be passed to contract call (ABI encoded parameters)
    ) external payable notFrozen {
        require(receiver != address(0), "Incorrect receiver address");
        (address originalToken, uint256 originalChainID, uint256 valueWithoutFee) = _deposit(
            token,
            value,
            toChainId
        );
        emit BridgeToContract(
            originalToken,
            originalChainID,
            token,
            receiver,
            valueWithoutFee,
            toChainId,
            toContract,
            data
        );
    }

    // Claim tokens from the bridge and call the contract with 'data' parameters
    function claimToContract(
        address originalToken, // original token
        uint256 originalChainID, // original chain ID
        bytes32 txId, // deposit transaction hash on fromChain
        address to, // receiver address
        uint256 value, // value of tokens
        uint256 fromChainId, // chain ID where user deposited
        address toContract, // this contract will be called on destination chain
        bytes memory data, // this data will be passed to contract call (ABI encoded parameters)
        bytes[] memory sig // authority signatures
    ) external notFrozen {
        require(
            !isTxProcessed[fromChainId][txId],
            "Transaction already processed"
        );
        bytes32 key = keccak256(
            abi.encodePacked(originalToken, originalChainID)
        );
        require(addedTokens[key].token != address(0), "token not exist");
        isTxProcessed[fromChainId][txId] = true;
        // Check signature
        {
            address must = addedTokens[key].authority;
            bytes32 messageHash = keccak256(
                abi.encodePacked(
                    originalToken,
                    originalChainID,
                    to,
                    value,
                    txId,
                    fromChainId,
                    block.chainid,
                    address(this),
                    toContract,
                    data
                )
            );
            checkSignatures(must, messageHash, sig);
        }

        {
            address token = addedTokens[key].wrappedToken;
            // Call toContract
            if (isContract(toContract) && toContract != address(this)) {
                if (token == address(0) && originalToken == NATIVE_COINS) {
                    token = originalToken;
                    IContractCaller(contractCaller).callContract{value: value}(
                        to,
                        token,
                        value,
                        toContract,
                        data
                    );
                } else {
                    if (token != address(0)) {
                        IERC20TokenCloned(token).mint(contractCaller, value);
                    } else {
                        token = originalToken;
                        tokenDeposits[token] -= value;
                        token.safeTransfer(contractCaller, value);
                    }
                    IContractCaller(contractCaller).callContract(
                        to,
                        token,
                        value,
                        toContract,
                        data
                    );
                }
            } else {
                // if not contract
                if (token != address(0)) {
                    IERC20TokenCloned(token).mint(to, value);
                } else {
                    token = originalToken;
                    if (token == NATIVE_COINS) {
                        to.safeTransferETH(value);
                    } else {
                        tokenDeposits[token] -= value;
                        token.safeTransfer(to, value);
                    }
                }
            }
            emit ClaimToContract(
                originalToken,
                originalChainID,
                token,
                to,
                value,
                txId,
                fromChainId,
                toContract
            );
        }
    }

    function depositTokens(
        address receiver, // address of token receiver on destination chain
        address token, // token that user send (if token address < 32, then send native coin)
        uint256 value, // tokens value
        uint256 toChainId // destination chain Id where will be claimed tokens
    ) external payable notFrozen {
        require(receiver != address(0), "Incorrect receiver address");
        (address originalToken, uint256 originalChainID, uint256 valueWithoutFee) = _deposit(
            token,
            value,
            toChainId
        );
        emit Deposit(
            originalToken,
            originalChainID,
            token,
            receiver,
            valueWithoutFee,
            toChainId
        );
    }

    function _deposit(
        address token, // token that user send (if token is address(1), then send native coin)
        uint256 value, // tokens value
        uint256 toChainId // destination chain Id where will be claimed tokens
    ) internal returns (address originalToken, uint256 originalChainID, uint256 valueWithoutFee) {
        require(isSupported[toChainId] && toChainId != block.chainid, "Destination chain not supported");
        uint256 fee = getBridgeFee(token); // fee in percent with 4 decimals
        if (fee !=0) {
            fee = value * fee / 1000000; // fee amount
            valueWithoutFee = value - fee;
            if (fee != 0) {
                if (token == NATIVE_COINS) {
                    feeTo.safeTransferETH(fee);
                } else {
                    token.safeTransferFrom(msg.sender, feeTo, fee);
                }
                emit Fee(msg.sender, token, fee);
            }
        } else {
            valueWithoutFee = value;
        }

        bytes32 key = nativeToToken[token];
        require(uint256(key) != 0, "Token wasn't added");
        originalToken = addedTokens[key].token;
        originalChainID = addedTokens[key].chainID;
        if (token == NATIVE_COINS) {
            require(value <= msg.value, "Wrong value");
        } else {
            if (addedTokens[key].wrappedToken == token) {
                IERC20TokenCloned(token).burnFrom(msg.sender, valueWithoutFee);
            } else {
                tokenDeposits[token] += valueWithoutFee;
                token.safeTransferFrom(msg.sender, address(this), valueWithoutFee);
            }
        }
    }

    // claim
    function claim(
        address originalToken, // original token
        uint256 originalChainID, // original chain ID
        bytes32 txId, // deposit transaction hash on fromChain
        address to, // user address
        uint256 value, // value of tokens
        uint256 fromChainId, // chain ID where user deposited
        bytes[] memory sig // authority signatures
    ) external notFrozen {
        require(
            !isTxProcessed[fromChainId][txId],
            "Transaction already processed"
        );
        bytes32 key = keccak256(
            abi.encodePacked(originalToken, originalChainID)
        );
        require(addedTokens[key].token != address(0), "token not exist");
        isTxProcessed[fromChainId][txId] = true;
        {
            address must = addedTokens[key].authority;
            bytes32 messageHash = keccak256(
                abi.encodePacked(
                    originalToken,
                    originalChainID,
                    to,
                    value,
                    txId,
                    fromChainId,
                    block.chainid,
                    address(this)
                )
            );
            checkSignatures(must, messageHash, sig);
        }
        address token = addedTokens[key].wrappedToken;
        if (token != address(0)) {
            IERC20TokenCloned(token).mint(to, value);
        } else {
            token = originalToken;
            if (token == NATIVE_COINS) {
                to.safeTransferETH(value);
            } else {
                tokenDeposits[token] -= value;
                token.safeTransfer(to, value);
            }
        }
        emit Claim(
            originalToken,
            originalChainID,
            token,
            to,
            value,
            txId,
            fromChainId
        );
    }

    // Signature methods
    function checkSignatures(
        address must,
        bytes32 messageHash,
        bytes[] memory sig
    ) internal view {
        messageHash = prefixed(messageHash);
        uint256 required;
        uint256 uniqSig;
        uint256 set; // maximum number of authorities is 255
        for (uint256 i = 0; i < sig.length; i++) {
            address authority = recoverSigner(messageHash, sig[i]);
            uint256 index = authorities.indexOf(authority);
            uint256 mask = 1 << index;
            if (index != 0 && (set & mask) == 0) {
                set |= mask;
                uniqSig++;
                if (requiredAuthorities[authority]) required++;
            }
            if (authority == must) must = address(0);   // must authority for specific token may not be approved by other authorities
        }
        require(threshold <= uniqSig, "Require more signatures");
        require(
            must == address(0) && required >= minRequiredAuthorities,
            "The required authorities didn't sign"
        );
    }

    function splitSignature(bytes memory sig)
        internal
        pure
        returns (
            uint8 v,
            bytes32 r,
            bytes32 s
        )
    {
        require(sig.length == 65);
        assembly {
            // first 32 bytes, after the length prefix
            r := mload(add(sig, 32))
            // second 32 bytes
            s := mload(add(sig, 64))
            // final byte (first byte of the next 32 bytes)
            v := byte(0, mload(add(sig, 96)))
        }
    }

    function recoverSigner(bytes32 message, bytes memory sig)
        internal
        pure
        returns (address)
    {
        uint8 v;
        bytes32 r;
        bytes32 s;

        (v, r, s) = splitSignature(sig);

        return ecrecover(message, v, r, s);
    }

    // Builds a prefixed hash to mimic the behavior of eth_sign.
    function prefixed(bytes32 hash) internal pure returns (bytes32) {
        return
            keccak256(
                abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)
            );
    }

    function isContract(address account) internal view returns (bool) {
        // This method relies in extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }
}
        

Compiler Settings

{"outputSelection":{"*":{"*":["abi","metadata","devdoc","userdoc","storageLayout","evm.legacyAssembly","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","evm.gasEstimates","evm.assembly"],"":["ast"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{}}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"AddToken","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"uint256","name":"chainID","internalType":"uint256","indexed":false},{"type":"uint256","name":"decimals","internalType":"uint256","indexed":false},{"type":"string","name":"name","internalType":"string","indexed":false},{"type":"string","name":"symbol","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"BridgeToContract","inputs":[{"type":"address","name":"originalToken","internalType":"address","indexed":true},{"type":"uint256","name":"originalChainID","internalType":"uint256","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"receiver","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"uint256","name":"toChainId","internalType":"uint256","indexed":false},{"type":"address","name":"toContract","internalType":"address","indexed":false},{"type":"bytes","name":"data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"Claim","inputs":[{"type":"address","name":"originalToken","internalType":"address","indexed":true},{"type":"uint256","name":"originalChainID","internalType":"uint256","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"bytes32","name":"txId","internalType":"bytes32","indexed":false},{"type":"uint256","name":"fromChainId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ClaimToContract","inputs":[{"type":"address","name":"originalToken","internalType":"address","indexed":true},{"type":"uint256","name":"originalChainID","internalType":"uint256","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"bytes32","name":"txId","internalType":"bytes32","indexed":false},{"type":"uint256","name":"fromChainId","internalType":"uint256","indexed":false},{"type":"address","name":"toContract","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"CreatePair","inputs":[{"type":"address","name":"toToken","internalType":"address","indexed":false},{"type":"address","name":"fromToken","internalType":"address","indexed":false},{"type":"uint256","name":"fromChainId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Deposit","inputs":[{"type":"address","name":"originalToken","internalType":"address","indexed":true},{"type":"uint256","name":"originalChainID","internalType":"uint256","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"receiver","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"uint256","name":"toChainId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Fee","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Frozen","inputs":[{"type":"bool","name":"status","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RescuedERC20","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"address","name":"to","internalType":"address","indexed":false},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetAuthority","inputs":[{"type":"address","name":"authority","internalType":"address","indexed":false},{"type":"bool","name":"isEnable","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetBridgeFee","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetContractCaller","inputs":[{"type":"address","name":"newContractCaller","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SetFeeTo","inputs":[{"type":"address","name":"previousFeeTo","internalType":"address","indexed":false},{"type":"address","name":"newFeeTo","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SetFreezer","inputs":[{"type":"address","name":"freezer","internalType":"address","indexed":false},{"type":"bool","name":"isActive","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetRequiredAuthority","inputs":[{"type":"address","name":"authority","internalType":"address","indexed":false},{"type":"bool","name":"isEnable","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetSupportedChain","inputs":[{"type":"uint256","name":"chainID","internalType":"uint256","indexed":false},{"type":"bool","name":"isSupported","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetThreshold","inputs":[{"type":"uint256","name":"threshold","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetTokenAuthority","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"uint256","name":"chainId","internalType":"uint256","indexed":false},{"type":"address","name":"authority","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SetupMode","inputs":[{"type":"uint256","name":"time","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UpgradeRequest","inputs":[{"type":"address","name":"newContract","internalType":"address","indexed":false},{"type":"uint256","name":"validFrom","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addAuthorities","inputs":[{"type":"address[]","name":"_authorities","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addToken","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addWrappedToken","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"chainID","internalType":"uint256"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"symbol","internalType":"string"},{"type":"bytes[]","name":"sig","internalType":"bytes[]"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"bridgeToContract","inputs":[{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"toChainId","internalType":"uint256"},{"type":"address","name":"toContract","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"changeFounder","inputs":[{"type":"address","name":"newFounders","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[{"type":"address","name":"originalToken","internalType":"address"},{"type":"uint256","name":"originalChainID","internalType":"uint256"},{"type":"bytes32","name":"txId","internalType":"bytes32"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"fromChainId","internalType":"uint256"},{"type":"bytes[]","name":"sig","internalType":"bytes[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimToContract","inputs":[{"type":"address","name":"originalToken","internalType":"address"},{"type":"uint256","name":"originalChainID","internalType":"uint256"},{"type":"bytes32","name":"txId","internalType":"bytes32"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"fromChainId","internalType":"uint256"},{"type":"address","name":"toContract","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"bytes[]","name":"sig","internalType":"bytes[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"contractCaller","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"depositTokens","inputs":[{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"toChainId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"disableSetupMode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"enableSetupMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeTo","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"founders","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"freeze","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"frozen","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getAuthorities","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAuthoritiesNumber","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"fee","internalType":"uint256"}],"name":"getBridgeFee","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct BridgeV2.Token","components":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"chainID","internalType":"uint256"},{"type":"address","name":"wrappedToken","internalType":"address"},{"type":"address","name":"authority","internalType":"address"}]}],"name":"getToken","inputs":[{"type":"address","name":"originalToken","internalType":"address"},{"type":"uint256","name":"originalChainID","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct BridgeV2.Token","components":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"chainID","internalType":"uint256"},{"type":"address","name":"wrappedToken","internalType":"address"},{"type":"address","name":"authority","internalType":"address"}]}],"name":"getToken","inputs":[{"type":"address","name":"nativeToken","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct BridgeV2.TokenDetails[]","components":[{"type":"address","name":"token","internalType":"address"},{"type":"uint8","name":"decimals","internalType":"uint8"},{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"symbol","internalType":"string"}]}],"name":"getTokenList","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"newOwner","internalType":"address"},{"type":"address","name":"newFounders","internalType":"address"},{"type":"address","name":"_feeTo","internalType":"address"},{"type":"address","name":"_tokenImplementation","internalType":"address"},{"type":"uint256","name":"_threshold","internalType":"uint256"},{"type":"address[]","name":"_authorities","internalType":"address[]"},{"type":"string","name":"_nativeCoin","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isFreezer","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isSupported","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isTxProcessed","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minRequiredAuthorities","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeAuthorities","inputs":[{"type":"address[]","name":"_authorities","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"requestUpgrade","inputs":[{"type":"address","name":"newContract","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"requiredAuthorities","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueERC20","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"address","name":"to","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBridgeFee","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"fee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setContractCaller","inputs":[{"type":"address","name":"newContractCaller","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeTo","inputs":[{"type":"address","name":"newFeeTo","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFreezer","inputs":[{"type":"address","name":"freezer","internalType":"address"},{"type":"bool","name":"isActive","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRequiredAuthorities","inputs":[{"type":"address[]","name":"_authorities","internalType":"address[]"},{"type":"bool","name":"isActive","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSupportedChain","inputs":[{"type":"uint256[]","name":"_chainID","internalType":"uint256[]"},{"type":"bool","name":"_isSupported","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setThreshold","inputs":[{"type":"uint256","name":"_threshold","internalType":"uint256"},{"type":"uint256","name":"_minRequiredAuthorities","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTokenMustAuthority","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"chainID","internalType":"uint256"},{"type":"address","name":"authority","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"setupMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"threshold","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenDeposits","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tokenImplementation","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unfreeze","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"newContract","internalType":"address"},{"type":"uint64","name":"validFrom","internalType":"uint64"}],"name":"upgradeData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"newContract","internalType":"address"}],"name":"upgradeTo","inputs":[]}]
              

Contract Creation Code

0x608060405234801561001057600080fd5b50600080546001600160a01b03191660011790556158ca806100336000396000f3fe6080604052600436106102885760003560e01c8063648a58961161015a578063d04567f3116100c1578063f2fde38b1161007a578063f2fde38b14610876578063f391b57314610896578063f46901ed146108c6578063fa087671146108e6578063fa220f621461093f578063fab9fa531461095f57600080fd5b8063d04567f314610799578063d48bfca7146107ae578063df42fd36146107ce578063e4d7a86314610809578063e6074da714610829578063e8eccb661461085657600080fd5b80638f715701116101135780638f715701146106e257806393c32e06146106f7578063a0fd9ec814610717578063a85c33cd14610737578063b9c3620914610757578063c21b48651461077757600080fd5b8063648a58961461060f5780636a28f0001461062f5780636b9f97ef146106445780636c65fd6a146106645780638d60cded146106945780638da5cb5b146106c457600080fd5b80633cb3e9dc116101fe5780635417b02c116101b75780635417b02c146104e057806354cf428a1461050057806359770438146105205780635d799f87146105ba5780635e14e319146105da57806362a5af3b146105fa57600080fd5b80633cb3e9dc1461040d578063411b007e1461042357806342cde4e81461044357806343d7cce61461045957806344ddcb60146104ba578063487cda0d146104cd57600080fd5b8063273cbaa011610250578063273cbaa014610356578063278fa3e9146103785780632a94a9c8146103985780632ca0814b146103b85780632f3a3d5d146103d85780633af84ac4146103f857600080fd5b8063017e7e581461028d578063054f7d9c146102ca57806313bf8126146102fb57806316a27ecd1461031f5780631c9499e814610334575b600080fd5b34801561029957600080fd5b506007546102ad906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102d657600080fd5b506007546102eb90600160a01b900460ff1681565b60405190151581526020016102c1565b34801561030757600080fd5b50610311600b5481565b6040519081526020016102c1565b34801561032b57600080fd5b506102ad61097f565b34801561034057600080fd5b5061035461034f36600461414e565b610a17565b005b34801561036257600080fd5b5061036b610d25565b6040516102c19190614222565b34801561038457600080fd5b506103546103933660046142cc565b610f4f565b3480156103a457600080fd5b506103546103b3366004614308565b6110d3565b3480156103c457600080fd5b506103546103d3366004614375565b61118f565b3480156103e457600080fd5b506006546102ad906001600160a01b031681565b34801561040457600080fd5b506103116113a2565b34801561041957600080fd5b5061031160135481565b34801561042f57600080fd5b50600d546102ad906001600160a01b031681565b34801561044f57600080fd5b5061031160055481565b34801561046557600080fd5b506104796104743660046143b6565b6113b2565b6040516102c1919081516001600160a01b03908116825260208084015190830152604080840151821690830152606092830151169181019190915260800190565b6103546104c83660046143e0565b611458565b6103546104db366004614460565b611543565b3480156104ec57600080fd5b506103116104fb366004614308565b61164c565b34801561050c57600080fd5b50600e546102ad906001600160a01b031681565b34801561052c57600080fd5b5061047961053b366004614308565b60408051608080820183526000808352602080840182905283850182905260609384018290526001600160a01b03958616825260108152848220548252600f8152908490208451928301855280548616835260018101549183019190915260028101548516938201939093526003909201549092169181019190915290565b3480156105c657600080fd5b506103546105d53660046144a2565b6116b0565b3480156105e657600080fd5b506103546105f53660046144e6565b6117c3565b34801561060657600080fd5b5061035461187e565b34801561061b57600080fd5b5061035461062a3660046143b6565b611912565b34801561063b57600080fd5b50610354611a0b565b34801561065057600080fd5b5061035461065f366004614308565b611ab5565b34801561067057600080fd5b506102eb61067f366004614308565b600a6020526000908152604090205460ff1681565b3480156106a057600080fd5b506102eb6106af36600461451d565b60116020526000908152604090205460ff1681565b3480156106d057600080fd5b506000546001600160a01b03166102ad565b3480156106ee57600080fd5b50610354611b90565b34801561070357600080fd5b50610354610712366004614308565b611c0b565b34801561072357600080fd5b50610354610732366004614536565b611d17565b34801561074357600080fd5b506103546107523660046145cd565b611e5f565b34801561076357600080fd5b50610354610772366004614683565b612158565b34801561078357600080fd5b5061078c612253565b6040516102c191906146a5565b3480156107a557600080fd5b506103546122b8565b3480156107ba57600080fd5b506103546107c9366004614308565b612328565b3480156107da57600080fd5b506102eb6107e9366004614683565b600860209081526000928352604080842090915290825290205460ff1681565b34801561081557600080fd5b506103546108243660046146f2565b612590565b34801561083557600080fd5b50610311610844366004614308565b60096020526000908152604090205481565b34801561086257600080fd5b50610354610871366004614375565b612a60565b34801561088257600080fd5b50610354610891366004614308565b612ba2565b3480156108a257600080fd5b506102eb6108b1366004614308565b60126020526000908152604090205460ff1681565b3480156108d257600080fd5b506103546108e1366004614308565b612cdd565b3480156108f257600080fd5b50600c54610918906001600160a01b03811690600160a01b90046001600160401b031682565b604080516001600160a01b0390931683526001600160401b039091166020830152016102c1565b34801561094b57600080fd5b5061035461095a3660046147ae565b612dc3565b34801561096b57600080fd5b5061035461097a366004614536565b61331e565b60408051808201909152600c546001600160a01b0381168252600160a01b90046001600160401b03166020820181905260009190421180156109ca575080516001600160a01b031615155b610a115760405162461bcd60e51b8152602060048201526013602482015272155c19dc985919481b9bdd08185b1b1bddd959606a1b60448201526064015b60405180910390fd5b51919050565b600754600160a01b900460ff1615610a415760405162461bcd60e51b8152600401610a089061486b565b600082815260086020908152604080832088845290915290205460ff1615610aab5760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a08565b60008787604051602001610ac0929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316610b0d5760405162461bcd60e51b8152600401610a08906148b7565b60008381526008602090815260408083208984528252808320805460ff19166001179055838352600f825280832060030154905160608c811b6bffffffffffffffffffffffff1990811694830194909452603482018c905289811b8416605483015260688201899052608882018b905260a882018890524660c883015230901b90921660e88301526001600160a01b0316919060fc01604051602081830303815290604052805190602001209050610bc6828286613440565b50506000818152600f60205260409020600201546001600160a01b03168015610c50576040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528216906340c10f1990604401600060405180830381600087803b158015610c3357600080fd5b505af1158015610c47573d6000803e3d6000fd5b50505050610cbe565b50876000196001600160a01b03821601610c7c57610c776001600160a01b03871686613643565b610cbe565b6001600160a01b03811660009081526009602052604081208054879290610ca49084906148f6565b90915550610cbe90506001600160a01b038216878761370c565b6040805189815260208101879052908101889052606081018590526001600160a01b0380881691838216918c16907f11d59cd9a05f00f00dae480666f9155193ed03ea6f17496757f3adcc07c2670d906080015b60405180910390a4505050505050505050565b60606000610d3260035490565b90506000816001600160401b03811115610d4e57610d4e613fed565b604051908082528060200260200182016040528015610da257816020015b6040805160808101825260008082526020820152606091810182905281810191909152815260200190600190039081610d6c5790505b50905060005b82811015610f48576000610dbd600383613820565b90506040518060800160405280826001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3b9190614909565b60ff168152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610e81573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ea9919081019061492c565b8152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610eec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f14919081019061492c565b815250838381518110610f2957610f296149a2565b6020026020010181905250508080610f40906149b8565b915050610da8565b5092915050565b33610f626000546001600160a01b031690565b6001600160a01b031614610f885760405162461bcd60e51b8152600401610a08906149d1565b60008383604051602001610f9d929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316610fea5760405162461bcd60e51b8152600401610a08906148b7565b6000818152600f60205260409020600301546001600160a01b03166110515760405162461bcd60e51b815260206004820152601c60248201527f6368616e676520617574686f72697479206e6f7420616c6c6f776564000000006044820152606401610a08565b6001600160a01b03821661106457600080fd5b6000818152600f602090815260409182902060030180546001600160a01b0319166001600160a01b038681169182179092558351878152928301528616917fee5ad7c073e09e589f00215f80efe0e7c6d5b9c4d19f5b85660a348b28ae867f910160405180910390a250505050565b336110e66000546001600160a01b031690565b6001600160a01b03161461110c5760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061111d57504281105b6111395760405162461bcd60e51b8152600401610a0890614a06565b600e80546001600160a01b0319166001600160a01b0384169081179091556040519081527f850b65e0a4a0af8155b0d56212b309166a3618bcd7ba7c1e83f09f3e721f294c906020015b60405180910390a15050565b336111a26000546001600160a01b031690565b6001600160a01b0316146111c85760405162461bcd60e51b8152600401610a08906149d1565b600b5480158015906111d957504281105b6111f55760405162461bcd60e51b8152600401610a0890614a06565b60ff8261120160015490565b61120b9190614a31565b1061124f5760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a08565b60005b8281101561139c57600084848381811061126e5761126e6149a2565b90506020020160208101906112839190614308565b6001600160a01b0316036112a95760405162461bcd60e51b8152600401610a0890614a44565b6112db8484838181106112be576112be6149a2565b90506020020160208101906112d39190614308565b6001906138af565b6113215760405162461bcd60e51b8152602060048201526017602482015276105d5d1a1bdc9a5d1e48185b1c9958591e481859191959604a1b6044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993848483818110611354576113546149a2565b90506020020160208101906113699190614308565b604080516001600160a01b039092168252600160208301520160405180910390a180611394816149b8565b915050611252565b50505050565b60006113ad60015490565b905090565b604080516080810182526000808252602082018190529181018290526060810191909152600f600084846040516020016113ed929190614895565b60408051601f198184030181529181528151602092830120835282820193909352908201600020825160808101845281546001600160a01b03908116825260018301549382019390935260028201548316938101939093526003015416606082015290505b92915050565b600754600160a01b900460ff16156114825760405162461bcd60e51b8152600401610a089061486b565b6001600160a01b0386166114d85760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b60008060006114e8888888613921565b925092509250886001600160a01b0316886001600160a01b0316846001600160a01b03167feaa11317bb61110cf1035a22a7b6b4c716b909b47954d51ee13de1627fdf0f5085858b8b8b604051610d12959493929190614a6a565b600754600160a01b900460ff161561156d5760405162461bcd60e51b8152600401610a089061486b565b6001600160a01b0384166115c35760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b60008060006115d3868686613921565b925092509250866001600160a01b0316866001600160a01b0316846001600160a01b03167fc9e84ed7aa56cf1771d0373f4b6380ccc9c7cdae154f287abf95c48f72e7f0cf85858960405161163b939291909283526020830191909152604082015260600190565b60405180910390a450505050505050565b6001600160a01b0381166000908152601460205260408120549081900361169d5750506000805260146020527f4f26c3876aa9f4b92579780beea1161a61f87ebf1ec6ee865b299e447ecba99c5490565b80620186a0036116ab575060005b919050565b336116c36000546001600160a01b031690565b6001600160a01b0316146116e95760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b0382166000818152600960205260408082205490516370a0823160e01b8152306004820152919290916370a0823190602401602060405180830381865afa15801561173f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117639190614aa8565b61176d91906148f6565b90506117836001600160a01b038416838361370c565b7f2c5650189f92c7058626efc371b51fe7e71f37dacb696bc7cad0b1320931974a8383836040516117b693929190614ac1565b60405180910390a1505050565b336117d66000546001600160a01b031690565b6001600160a01b0316146117fc5760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b0382166118225760405162461bcd60e51b8152600401610a0890614a44565b6001600160a01b0382166000818152600a6020908152604091829020805460ff19168515159081179091558251938452908301527feabe320fe7911eab2e5125ac393caa5937659b712f0c3ac43316c61d4bc088019101611183565b6000546001600160a01b03163314806118a557503360009081526002602052604090205415155b806118bf5750336000908152600a602052604090205460ff165b6118c857600080fd5b6007805460ff60a01b1916600160a01b179055604051600181527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a1565b336119256000546001600160a01b031690565b6001600160a01b03161461194b5760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061195c57504281105b6119785760405162461bcd60e51b8152600401610a0890614a06565b620186a08211156119ba5760405162461bcd60e51b815260206004820152600c60248201526b546f6f20686967682066656560a01b6044820152606401610a08565b6001600160a01b038316600081815260146020908152604091829020859055815192835282018490527fa065abcf8156e439379371f7924f05c22b16f14de6a1448c5bcbdc525b46dd8591016117b6565b33611a1e6000546001600160a01b031690565b6001600160a01b031614611a445760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590611a5557504281105b611a715760405162461bcd60e51b8152600401610a0890614a06565b6007805460ff60a01b19169055604051600081527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e9060200160405180910390a150565b33611ac86000546001600160a01b031690565b6001600160a01b031614611aee5760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b038116611b145760405162461bcd60e51b8152600401610a0890614a44565b6040805180820182526001600160a01b038316808252426001600160401b0381166020938401819052600c80546001600160e01b0319168417600160a01b909202919091179055835191825291810182905290917fd990f8f4f90cd3307c50ab3d095cfb65516e999b7584aee60c0af83eb48118de9101611183565b33611ba36000546001600160a01b031690565b6001600160a01b031614611bc95760405162461bcd60e51b8152600401610a08906149d1565b611bd64262015180614a31565b600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611908565b600d546001600160a01b03163314611c655760405162461bcd60e51b815260206004820152601a60248201527f63616c6c6572206973206e6f742074686520666f756e646572730000000000006044820152606401610a08565b6001600160a01b038116611cbb5760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610a08565b600d546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600d80546001600160a01b0319166001600160a01b0392909216919091179055565b33611d2a6000546001600160a01b031690565b6001600160a01b031614611d505760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590611d6157504281105b611d7d5760405162461bcd60e51b8152600401610a0890614a06565b60005b83811015611e58578260126000878785818110611d9f57611d9f6149a2565b9050602002016020810190611db49190614308565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b79287858583818110611e0f57611e0f6149a2565b9050602002016020810190611e249190614308565b604080516001600160a01b03909216825285151560208301520160405180910390a180611e50816149b8565b915050611d80565b5050505050565b468703611ea35760405162461bcd60e51b815260206004820152601260248201527127b7363c903337b932b4b3b7103a37b5b2b760711b6044820152606401610a08565b60008888604051602001611eb8929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b031615611f2c5760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b600089898989898989604051602001611f4b9796959493929190614ae5565b604051602081830303815290604052805190602001209050611f6f60008285613440565b60008787604051602001611f84929190614b36565b604051602081830303815290604052905060008686604051602001611faa929190614b5a565b60408051601f19818403018152919052600654909150600090611fda906001600160a01b03908116908f16613c15565b9050806001600160a01b0316631624f6c684848e6040518463ffffffff1660e01b815260040161200c93929190614b77565b600060405180830381600087803b15801561202657600080fd5b505af115801561203a573d6000803e3d6000fd5b505050508c600f600087815260200190815260200160002060000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508b600f60008781526020019081526020016000206001018190555080600f600087815260200190815260200160002060020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508460106000836001600160a01b03166001600160a01b031681526020019081526020016000208190555061210d8160036138af90919063ffffffff16565b507f7cedf5820723679f9a981ba7249d0ab5c6ecdb2f98392ef5a29051153b9e5a7d818e8e60405161214193929190614ac1565b60405180910390a150505050505050505050505050565b3361216b6000546001600160a01b031690565b6001600160a01b0316146121915760405162461bcd60e51b8152600401610a08906149d1565b600b5480158015906121a257504281105b6121be5760405162461bcd60e51b8152600401610a0890614a06565b82158015906121cf57506001548311155b80156121db5750828211155b6122195760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a08565b601382905560058390556040518381527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf906020016117b6565b606060016000018054806020026020016040519081016040528092919081815260200182805480156122ae57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612290575b5050505050905090565b336122cb6000546001600160a01b031690565b6001600160a01b0316146122f15760405162461bcd60e51b8152600401610a08906149d1565b6000600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611908565b6001600160a01b038116600090815260106020526040902054156123845760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b6000816001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa1580156123c4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123ec919081019061492c565b90506000826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561242e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612456919081019061492c565b90506000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612498573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124bc9190614909565b60ff169050600084466040516020016124d6929190614895565b60408051601f1981840301815291815281516020928301206000818152600f845282812080546001600160a01b038b166001600160a01b03199182168117835546600184015560029092018054909116905581526010909352912081905590506125416003866138af565b50846001600160a01b03167fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c5263468487876040516125819493929190614bb0565b60405180910390a25050505050565b600754600160a01b900460ff16156125ba5760405162461bcd60e51b8152600401610a089061486b565b60008481526008602090815260408083208a845290915290205460ff16156126245760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a08565b60008989604051602001612639929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b03166126865760405162461bcd60e51b8152600401610a08906148b7565b60016008600087815260200190815260200160002060008a815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600f600083815260200190815260200160002060030160009054906101000a90046001600160a01b0316905060008b8b8a8a8d8b46308d8d6040516020016127169a99989796959493929190614be1565b604051602081830303815290604052805190602001209050612739828286613440565b50506000818152600f60205260409020600201546001600160a01b0316843b1515801561276f57506001600160a01b0385163014155b1561293e576001600160a01b03811615801561279457506001600160a01b038b166001145b1561280b5750600e54604051631490ba2d60e31b81528b916001600160a01b03169063a485d1689089906127d4908c90869084908c908c90600401614c62565b6000604051808303818588803b1580156127ed57600080fd5b505af1158015612801573d6000803e3d6000fd5b50505050506129f0565b6001600160a01b0381161561288557600e546040516340c10f1960e01b81526001600160a01b03918216600482015260248101899052908216906340c10f1990604401600060405180830381600087803b15801561286857600080fd5b505af115801561287c573d6000803e3d6000fd5b505050506128cf565b506001600160a01b038a16600090815260096020526040812080548c928992916128b09084906148f6565b9091555050600e546128cf906001600160a01b0383811691168961370c565b600e54604051631490ba2d60e31b81526001600160a01b039091169063a485d16890612907908b9085908c908b908b90600401614c62565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b505050506129f0565b6001600160a01b03811615612982576040516340c10f1960e01b81526001600160a01b038981166004830152602482018990528216906340c10f1990604401612907565b50896000196001600160a01b038216016129ae576129a96001600160a01b03891688613643565b6129f0565b6001600160a01b038116600090815260096020526040812080548992906129d69084906148f6565b909155506129f090506001600160a01b038216898961370c565b604080518b8152602081018990529081018a9052606081018790526001600160a01b038681166080830152808a1691838216918e16907f3d5595f71187e446858be0c0fa22a3dd315023362b3b056c5eada14baecfc1019060a00160405180910390a45050505050505050505050565b33612a736000546001600160a01b031690565b6001600160a01b031614612a995760405162461bcd60e51b8152600401610a08906149d1565b60005b81811015612b9d57612ad6838383818110612ab957612ab96149a2565b9050602002016020810190612ace9190614308565b600190613cb5565b612b225760405162461bcd60e51b815260206004820152601860248201527f417574686f7269747920646f6573206e6f7420657869737400000000000000006044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993838383818110612b5557612b556149a2565b9050602002016020810190612b6a9190614308565b604080516001600160a01b039092168252600060208301520160405180910390a180612b95816149b8565b915050612a9c565b505050565b600d546001600160a01b0316331480612bc557506000546001600160a01b031633145b612c1d5760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f742074686520666f756e6460448201526265727360e81b6064820152608401610a08565b6001600160a01b038116612c825760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a08565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b33612cf06000546001600160a01b031690565b6001600160a01b031614612d165760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590612d2757504281105b612d435760405162461bcd60e51b8152600401610a0890614a06565b6001600160a01b038216612d695760405162461bcd60e51b8152600401610a0890614a44565b600780546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca491016117b6565b6001600160a01b03891615801590612de357506001600160a01b03881615155b8015612df857506000546001600160a01b0316155b8015612e0c57506001600160a01b03871615155b612e1557600080fd5b600080546001600160a01b03199081166001600160a01b038c81169182178455600d8054909316908c16179091556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36001600160a01b038616612ec45760405162461bcd60e51b815260206004820152601960248201527f57726f6e6720746f6b656e496d706c656d656e746174696f6e000000000000006044820152606401610a08565b84600003612f065760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a08565b60ff83612f1260015490565b612f1c9190614a31565b10612f605760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a08565b60005b83811015613090576000858583818110612f7f57612f7f6149a2565b9050602002016020810190612f949190614308565b6001600160a01b031603612fba5760405162461bcd60e51b8152600401610a0890614a44565b612fcf8585838181106112be576112be6149a2565b6130155760405162461bcd60e51b8152602060048201526017602482015276105d5d1a1bdc9a5d1e48185b1c9958591e481859191959604a1b6044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993858583818110613048576130486149a2565b905060200201602081019061305d9190614308565b604080516001600160a01b039092168252600160208301520160405180910390a180613088816149b8565b915050612f63565b50600680546001600160a01b0319166001600160a01b0388161790556040516130b890613fc9565b604051809103906000f0801580156130d4573d6000803e3d6000fd5b50600e80546001600160a01b03199081166001600160a01b0393841617909155600780549091169189169182179055604080516000815260208101929092527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca4910160405180910390a160058590556040518581527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf9060200160405180910390a16001601260008686600081811061318f5761318f6149a2565b90506020020160208101906131a49190614308565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055507f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b792878484600081811061320f5761320f6149a2565b90506020020160208101906132249190614308565b604080516001600160a01b039092168252600160208301520160405180910390a160016013819055600b819055604051600091613265914690602001614895565b60408051601f1981840301815282825280516020918201206000818152600f835292832080546001600160a01b03191660019081178255469181018290559384905260109092527f8c6065603763fec3f5742441d3833f3f43b982453612d76adb39a885e3006b5f819055935090917fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c52639161330a916012908890889082908290614cc6565b60405180910390a250505050505050505050565b336133316000546001600160a01b031690565b6001600160a01b0316146133575760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061336857504281105b6133845760405162461bcd60e51b8152600401610a0890614a06565b60005b83811015611e585782601160008787858181106133a6576133a66149a2565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055507f96fb1460e35cd6722dbde21ee5de56c0c1e73920214010e33b2591763744fd8b858583818110613405576134056149a2565b90506020020135846040516134269291909182521515602082015260400190565b60405180910390a180613438816149b8565b915050613387565b613497826040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b915060008080805b84518110156135775760006134cd878784815181106134c0576134c06149a2565b6020026020010151613df7565b6001600160a01b0381166000908152600260205260409020549091506001811b81158015906134fc5750848116155b1561354357938417938561350f816149b8565b6001600160a01b03851660009081526012602052604090205490975060ff16159050613543578661353f816149b8565b9750505b896001600160a01b0316836001600160a01b03160361356157600099505b505050808061356f906149b8565b91505061349f565b508160055411156135ca5760405162461bcd60e51b815260206004820152601760248201527f52657175697265206d6f7265207369676e6174757265730000000000000000006044820152606401610a08565b6001600160a01b0386161580156135e357506013548310155b61363b5760405162461bcd60e51b8152602060048201526024808201527f54686520726571756972656420617574686f726974696573206469646e27742060448201526339b4b3b760e11b6064820152608401610a08565b505050505050565b604080516000808252602082019092526001600160a01b03841690839060405161366d9190614d06565b60006040518083038185875af1925050503d80600081146136aa576040519150601f19603f3d011682016040523d82523d6000602084013e6136af565b606091505b5050905080612b9d5760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610a08565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916137689190614d06565b6000604051808303816000865af19150503d80600081146137a5576040519150601f19603f3d011682016040523d82523d6000602084013e6137aa565b606091505b50915091508180156137d45750805115806137d45750808060200190518101906137d49190614d22565b611e585760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610a08565b8154600090821061387e5760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b6064820152608401610a08565b826000018281548110613893576138936149a2565b6000918252602090912001546001600160a01b03169392505050565b6001600160a01b038116600090815260018301602052604081205461391957508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155611452565b506000611452565b6000818152601160205260408120548190819060ff1680156139435750468414155b61398f5760405162461bcd60e51b815260206004820152601f60248201527f44657374696e6174696f6e20636861696e206e6f7420737570706f72746564006044820152606401610a08565b600061399a8761164c565b90508015613a5857620f42406139b08288614d3f565b6139ba9190614d56565b90506139c681876148f6565b91508015613a53576000196001600160a01b038816016139fb576007546139f6906001600160a01b031682613643565b613a17565b600754613a17906001600160a01b038981169133911684613e76565b7f6ded982279c8387ad8a63e73385031a3807c1862e633f06e09d11bcb6e282f60338883604051613a4a93929190614ac1565b60405180910390a15b613a5c565b8591505b6001600160a01b03871660009081526010602052604081205490819003613aba5760405162461bcd60e51b8152602060048201526012602482015271151bdad95b881dd85cdb89dd08185919195960721b6044820152606401610a08565b6000818152600f6020526040902080546001909101546001600160a01b0391821696509450881660001901613b2c5734871115613b275760405162461bcd60e51b815260206004820152600b60248201526a57726f6e672076616c756560a81b6044820152606401610a08565b613c0a565b6000818152600f60205260409020600201546001600160a01b03808a16911603613bc75760405163079cc67960e41b8152336004820152602481018490526001600160a01b038916906379cc6790906044016020604051808303816000875af1158015613b9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bc19190614d22565b50613c0a565b6001600160a01b03881660009081526009602052604081208054859290613bef908490614a31565b90915550613c0a90506001600160a01b038916333086613e76565b505093509350939050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b0381166114525760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610a08565b6001600160a01b03811660009081526001830160205260408120548015613ded576000613ce36001836148f6565b8554909150600090613cf7906001906148f6565b90506000866000018281548110613d1057613d106149a2565b60009182526020909120015487546001600160a01b0390911691508190889085908110613d3f57613d3f6149a2565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055613d73836001614a31565b6001600160a01b03821660009081526001890160205260409020558654879080613d9f57613d9f614d78565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506114529350505050565b6000915050611452565b600080600080613e0685613f9a565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa158015613e61573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b600080856001600160a01b03166323b872dd868686604051602401613e9d93929190614ac1565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051613ed69190614d06565b6000604051808303816000865af19150503d8060008114613f13576040519150601f19603f3d011682016040523d82523d6000602084013e613f18565b606091505b5091509150818015613f42575080511580613f42575080806020019051810190613f429190614d22565b61363b5760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610a08565b60008060008351604114613fad57600080fd5b5050506020810151604082015160609092015160001a92909190565b610b0680614d8f83390190565b80356001600160a01b03811681146116ab57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561402b5761402b613fed565b604052919050565b60006001600160401b0382111561404c5761404c613fed565b50601f01601f191660200190565b600082601f83011261406b57600080fd5b813561407e61407982614033565b614003565b81815284602083860101111561409357600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f8301126140c157600080fd5b813560206001600160401b03808311156140dd576140dd613fed565b8260051b6140ec838201614003565b938452858101830193838101908886111561410657600080fd5b84880192505b85831015614142578235848111156141245760008081fd5b6141328a87838c010161405a565b835250918401919084019061410c565b98975050505050505050565b600080600080600080600060e0888a03121561416957600080fd5b61417288613fd6565b9650602088013595506040880135945061418e60608901613fd6565b93506080880135925060a0880135915060c08801356001600160401b038111156141b757600080fd5b6141c38a828b016140b0565b91505092959891949750929550565b60005b838110156141ed5781810151838201526020016141d5565b50506000910152565b6000815180845261420e8160208601602086016141d2565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156142be57888303603f19018552815180516001600160a01b031684528781015160ff16888501528681015160808886018190529061428d828701826141f6565b915050606080830151925085820381870152506142aa81836141f6565b968901969450505090860190600101614249565b509098975050505050505050565b6000806000606084860312156142e157600080fd5b6142ea84613fd6565b9250602084013591506142ff60408501613fd6565b90509250925092565b60006020828403121561431a57600080fd5b61432382613fd6565b9392505050565b60008083601f84011261433c57600080fd5b5081356001600160401b0381111561435357600080fd5b6020830191508360208260051b850101111561436e57600080fd5b9250929050565b6000806020838503121561438857600080fd5b82356001600160401b0381111561439e57600080fd5b6143aa8582860161432a565b90969095509350505050565b600080604083850312156143c957600080fd5b6143d283613fd6565b946020939093013593505050565b60008060008060008060c087890312156143f957600080fd5b61440287613fd6565b955061441060208801613fd6565b9450604087013593506060870135925061442c60808801613fd6565b915060a08701356001600160401b0381111561444757600080fd5b61445389828a0161405a565b9150509295509295509295565b6000806000806080858703121561447657600080fd5b61447f85613fd6565b935061448d60208601613fd6565b93969395505050506040820135916060013590565b600080604083850312156144b557600080fd5b6144be83613fd6565b91506144cc60208401613fd6565b90509250929050565b80151581146144e357600080fd5b50565b600080604083850312156144f957600080fd5b61450283613fd6565b91506020830135614512816144d5565b809150509250929050565b60006020828403121561452f57600080fd5b5035919050565b60008060006040848603121561454b57600080fd5b83356001600160401b0381111561456157600080fd5b61456d8682870161432a565b9094509250506020840135614581816144d5565b809150509250925092565b60008083601f84011261459e57600080fd5b5081356001600160401b038111156145b557600080fd5b60208301915083602082850101111561436e57600080fd5b60008060008060008060008060c0898b0312156145e957600080fd5b6145f289613fd6565b9750602089013596506040890135955060608901356001600160401b038082111561461c57600080fd5b6146288c838d0161458c565b909750955060808b013591508082111561464157600080fd5b61464d8c838d0161458c565b909550935060a08b013591508082111561466657600080fd5b506146738b828c016140b0565b9150509295985092959890939650565b6000806040838503121561469657600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156146e65783516001600160a01b0316835292840192918401916001016146c1565b50909695505050505050565b60008060008060008060008060006101208a8c03121561471157600080fd5b61471a8a613fd6565b985060208a0135975060408a0135965061473660608b01613fd6565b955060808a0135945060a08a0135935061475260c08b01613fd6565b925060e08a01356001600160401b038082111561476e57600080fd5b61477a8d838e0161405a565b93506101008c013591508082111561479157600080fd5b5061479e8c828d016140b0565b9150509295985092959850929598565b600080600080600080600080600060e08a8c0312156147cc57600080fd5b6147d58a613fd6565b98506147e360208b01613fd6565b97506147f160408b01613fd6565b96506147ff60608b01613fd6565b955060808a0135945060a08a01356001600160401b038082111561482257600080fd5b61482e8d838e0161432a565b909650945060c08c013591508082111561484757600080fd5b506148548c828d0161458c565b915080935050809150509295985092959850929598565b60208082526010908201526f213934b233b29034b990333937bd32b760811b604082015260600190565b60609290921b6bffffffffffffffffffffffff19168252601482015260340190565b6020808252600f908201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b81810381811115611452576114526148e0565b60006020828403121561491b57600080fd5b815160ff8116811461432357600080fd5b60006020828403121561493e57600080fd5b81516001600160401b0381111561495457600080fd5b8201601f8101841361496557600080fd5b805161497361407982614033565b81815285602083850101111561498857600080fd5b6149998260208301602086016141d2565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016149ca576149ca6148e0565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601190820152704e6f7420696e207365747570206d6f646560781b604082015260600190565b80820180821115611452576114526148e0565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b85815284602082015283604082015260018060a01b038316606082015260a060808201526000614a9d60a08301846141f6565b979650505050505050565b600060208284031215614aba57600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6bffffffffffffffffffffffff198860601b16815286601482015285603482015283856054830137600084820160548101600081528486823750600093016054019283525090979650505050505050565b6702bb930b83832b2160c51b81528183600883013760009101600801908152919050565b605760f81b81528183600183013760009101600101908152919050565b606081526000614b8a60608301866141f6565b8281036020840152614b9c81866141f6565b91505060ff83166040830152949350505050565b848152836020820152608060408201526000614bcf60808301856141f6565b8281036060840152614a9d81856141f6565b60006bffffffffffffffffffffffff19808d60601b1683528b6014840152808b60601b1660348401528960488401528860688401528760888401528660a8840152808660601b1660c8840152808560601b1660dc840152508251614c4c8160f08501602087016141d2565b9190910160f0019b9a5050505050505050505050565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a060808201819052600090614a9d908301846141f6565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b868152856020820152608060408201526000614ce6608083018688614c9d565b8281036060840152614cf9818587614c9d565b9998505050505050505050565b60008251614d188184602087016141d2565b9190910192915050565b600060208284031215614d3457600080fd5b8151614323816144d5565b8082028115828204841417611452576114526148e0565b600082614d7357634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fdfe608060405234801561001057600080fd5b50600080546001600160a01b03191633179055610ad4806100326000396000f3fe60806040526004361061003f5760003560e01c80635431c94e146100445780638943ec0214610066578063a485d16814610086578063e78cea9214610099575b600080fd5b34801561005057600080fd5b5061006461005f36600461081e565b6100d5565b005b34801561007257600080fd5b50610064610081366004610857565b610294565b6100646100943660046108f6565b6102ea565b3480156100a557600080fd5b506000546100b9906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b60008054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014a91906109e9565b6001600160a01b0316336001600160a01b03161461019c5760405162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b60448201526064015b60405180910390fd5b60006001600160a01b0383166101c65750476101c16001600160a01b03831682610510565b610244565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561020a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022e9190610a0d565b90506102446001600160a01b03841683836105de565b604080516001600160a01b038086168252841660208201529081018290527f0f51b71e5e9ee881072b57bf4022b60435e0000ad377b5c1434da39471002b559060600160405180910390a1505050565b6000546001600160a01b038581169116146102e45760405162461bcd60e51b815260206004820152601060248201526f4f6e6c792066726f6d2062726964676560801b6044820152606401610193565b50505050565b6000546001600160a01b031633146103325760405162461bcd60e51b815260206004820152600b60248201526a4f6e6c792062726964676560a81b6044820152606401610193565b6000196001600160a01b038516016103e95734925060006103538447610a26565b90506000836001600160a01b031685846040516103709190610a4d565b60006040518083038185875af1925050503d80600081146103ad576040519150601f19603f3d011682016040523d82523d6000602084013e6103b2565b606091505b5050905080156103c9576103c68247610a26565b94505b84156103e2576103e26001600160a01b03881686610510565b5050610509565b6103fd6001600160a01b03851683856106f2565b6000826001600160a01b03166000836040516104199190610a4d565b60006040518083038185875af1925050503d8060008114610456576040519150601f19603f3d011682016040523d82523d6000602084013e61045b565b606091505b5050905080156104d857604051636eb1769f60e11b81523060048201526001600160a01b03848116602483015286169063dd62ed3e90604401602060405180830381865afa1580156104b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d59190610a0d565b93505b8315610507576104f36001600160a01b0386168460006106f2565b6105076001600160a01b03861687866105de565b505b5050505050565b604080516000808252602082019092526001600160a01b03841690839060405161053a9190610a4d565b60006040518083038185875af1925050503d8060008114610577576040519150601f19603f3d011682016040523d82523d6000602084013e61057c565b606091505b50509050806105d95760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610193565b505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161063a9190610a4d565b6000604051808303816000865af19150503d8060008114610677576040519150601f19603f3d011682016040523d82523d6000602084013e61067c565b606091505b50915091508180156106a65750805115806106a65750808060200190518101906106a69190610a7c565b6105095760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610193565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b179052915160009283929087169161074e9190610a4d565b6000604051808303816000865af19150503d806000811461078b576040519150601f19603f3d011682016040523d82523d6000602084013e610790565b606091505b50915091508180156107ba5750805115806107ba5750808060200190518101906107ba9190610a7c565b6105095760405162461bcd60e51b815260206004820152601e60248201527f5472616e7366657248656c7065723a20415050524f56455f4641494c454400006044820152606401610193565b6001600160a01b038116811461081b57600080fd5b50565b6000806040838503121561083157600080fd5b823561083c81610806565b9150602083013561084c81610806565b809150509250929050565b6000806000806060858703121561086d57600080fd5b843561087881610806565b935060208501359250604085013567ffffffffffffffff8082111561089c57600080fd5b818701915087601f8301126108b057600080fd5b8135818111156108bf57600080fd5b8860208285010111156108d157600080fd5b95989497505060200194505050565b634e487b7160e01b600052604160045260246000fd5b600080600080600060a0868803121561090e57600080fd5b853561091981610806565b9450602086013561092981610806565b935060408601359250606086013561094081610806565b9150608086013567ffffffffffffffff8082111561095d57600080fd5b818801915088601f83011261097157600080fd5b813581811115610983576109836108e0565b604051601f8201601f19908116603f011681019083821181831017156109ab576109ab6108e0565b816040528281528b60208487010111156109c457600080fd5b8260208601602083013760006020848301015280955050505050509295509295909350565b6000602082840312156109fb57600080fd5b8151610a0681610806565b9392505050565b600060208284031215610a1f57600080fd5b5051919050565b81810381811115610a4757634e487b7160e01b600052601160045260246000fd5b92915050565b6000825160005b81811015610a6e5760208186018101518583015201610a54565b506000920191825250919050565b600060208284031215610a8e57600080fd5b81518015158114610a0657600080fdfea26469706673582212208afe667ddb88db78c3484d988496ed61ef38a3f5b7fcea15a41c39ac1c0b566e64736f6c63430008130033a264697066735822122089a9415157d8f781cf8ced25f5811663759b67f6eabcfaff6a1c203a5fa516eb64736f6c63430008130033

Deployed ByteCode

0x6080604052600436106102885760003560e01c8063648a58961161015a578063d04567f3116100c1578063f2fde38b1161007a578063f2fde38b14610876578063f391b57314610896578063f46901ed146108c6578063fa087671146108e6578063fa220f621461093f578063fab9fa531461095f57600080fd5b8063d04567f314610799578063d48bfca7146107ae578063df42fd36146107ce578063e4d7a86314610809578063e6074da714610829578063e8eccb661461085657600080fd5b80638f715701116101135780638f715701146106e257806393c32e06146106f7578063a0fd9ec814610717578063a85c33cd14610737578063b9c3620914610757578063c21b48651461077757600080fd5b8063648a58961461060f5780636a28f0001461062f5780636b9f97ef146106445780636c65fd6a146106645780638d60cded146106945780638da5cb5b146106c457600080fd5b80633cb3e9dc116101fe5780635417b02c116101b75780635417b02c146104e057806354cf428a1461050057806359770438146105205780635d799f87146105ba5780635e14e319146105da57806362a5af3b146105fa57600080fd5b80633cb3e9dc1461040d578063411b007e1461042357806342cde4e81461044357806343d7cce61461045957806344ddcb60146104ba578063487cda0d146104cd57600080fd5b8063273cbaa011610250578063273cbaa014610356578063278fa3e9146103785780632a94a9c8146103985780632ca0814b146103b85780632f3a3d5d146103d85780633af84ac4146103f857600080fd5b8063017e7e581461028d578063054f7d9c146102ca57806313bf8126146102fb57806316a27ecd1461031f5780631c9499e814610334575b600080fd5b34801561029957600080fd5b506007546102ad906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102d657600080fd5b506007546102eb90600160a01b900460ff1681565b60405190151581526020016102c1565b34801561030757600080fd5b50610311600b5481565b6040519081526020016102c1565b34801561032b57600080fd5b506102ad61097f565b34801561034057600080fd5b5061035461034f36600461414e565b610a17565b005b34801561036257600080fd5b5061036b610d25565b6040516102c19190614222565b34801561038457600080fd5b506103546103933660046142cc565b610f4f565b3480156103a457600080fd5b506103546103b3366004614308565b6110d3565b3480156103c457600080fd5b506103546103d3366004614375565b61118f565b3480156103e457600080fd5b506006546102ad906001600160a01b031681565b34801561040457600080fd5b506103116113a2565b34801561041957600080fd5b5061031160135481565b34801561042f57600080fd5b50600d546102ad906001600160a01b031681565b34801561044f57600080fd5b5061031160055481565b34801561046557600080fd5b506104796104743660046143b6565b6113b2565b6040516102c1919081516001600160a01b03908116825260208084015190830152604080840151821690830152606092830151169181019190915260800190565b6103546104c83660046143e0565b611458565b6103546104db366004614460565b611543565b3480156104ec57600080fd5b506103116104fb366004614308565b61164c565b34801561050c57600080fd5b50600e546102ad906001600160a01b031681565b34801561052c57600080fd5b5061047961053b366004614308565b60408051608080820183526000808352602080840182905283850182905260609384018290526001600160a01b03958616825260108152848220548252600f8152908490208451928301855280548616835260018101549183019190915260028101548516938201939093526003909201549092169181019190915290565b3480156105c657600080fd5b506103546105d53660046144a2565b6116b0565b3480156105e657600080fd5b506103546105f53660046144e6565b6117c3565b34801561060657600080fd5b5061035461187e565b34801561061b57600080fd5b5061035461062a3660046143b6565b611912565b34801561063b57600080fd5b50610354611a0b565b34801561065057600080fd5b5061035461065f366004614308565b611ab5565b34801561067057600080fd5b506102eb61067f366004614308565b600a6020526000908152604090205460ff1681565b3480156106a057600080fd5b506102eb6106af36600461451d565b60116020526000908152604090205460ff1681565b3480156106d057600080fd5b506000546001600160a01b03166102ad565b3480156106ee57600080fd5b50610354611b90565b34801561070357600080fd5b50610354610712366004614308565b611c0b565b34801561072357600080fd5b50610354610732366004614536565b611d17565b34801561074357600080fd5b506103546107523660046145cd565b611e5f565b34801561076357600080fd5b50610354610772366004614683565b612158565b34801561078357600080fd5b5061078c612253565b6040516102c191906146a5565b3480156107a557600080fd5b506103546122b8565b3480156107ba57600080fd5b506103546107c9366004614308565b612328565b3480156107da57600080fd5b506102eb6107e9366004614683565b600860209081526000928352604080842090915290825290205460ff1681565b34801561081557600080fd5b506103546108243660046146f2565b612590565b34801561083557600080fd5b50610311610844366004614308565b60096020526000908152604090205481565b34801561086257600080fd5b50610354610871366004614375565b612a60565b34801561088257600080fd5b50610354610891366004614308565b612ba2565b3480156108a257600080fd5b506102eb6108b1366004614308565b60126020526000908152604090205460ff1681565b3480156108d257600080fd5b506103546108e1366004614308565b612cdd565b3480156108f257600080fd5b50600c54610918906001600160a01b03811690600160a01b90046001600160401b031682565b604080516001600160a01b0390931683526001600160401b039091166020830152016102c1565b34801561094b57600080fd5b5061035461095a3660046147ae565b612dc3565b34801561096b57600080fd5b5061035461097a366004614536565b61331e565b60408051808201909152600c546001600160a01b0381168252600160a01b90046001600160401b03166020820181905260009190421180156109ca575080516001600160a01b031615155b610a115760405162461bcd60e51b8152602060048201526013602482015272155c19dc985919481b9bdd08185b1b1bddd959606a1b60448201526064015b60405180910390fd5b51919050565b600754600160a01b900460ff1615610a415760405162461bcd60e51b8152600401610a089061486b565b600082815260086020908152604080832088845290915290205460ff1615610aab5760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a08565b60008787604051602001610ac0929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316610b0d5760405162461bcd60e51b8152600401610a08906148b7565b60008381526008602090815260408083208984528252808320805460ff19166001179055838352600f825280832060030154905160608c811b6bffffffffffffffffffffffff1990811694830194909452603482018c905289811b8416605483015260688201899052608882018b905260a882018890524660c883015230901b90921660e88301526001600160a01b0316919060fc01604051602081830303815290604052805190602001209050610bc6828286613440565b50506000818152600f60205260409020600201546001600160a01b03168015610c50576040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528216906340c10f1990604401600060405180830381600087803b158015610c3357600080fd5b505af1158015610c47573d6000803e3d6000fd5b50505050610cbe565b50876000196001600160a01b03821601610c7c57610c776001600160a01b03871686613643565b610cbe565b6001600160a01b03811660009081526009602052604081208054879290610ca49084906148f6565b90915550610cbe90506001600160a01b038216878761370c565b6040805189815260208101879052908101889052606081018590526001600160a01b0380881691838216918c16907f11d59cd9a05f00f00dae480666f9155193ed03ea6f17496757f3adcc07c2670d906080015b60405180910390a4505050505050505050565b60606000610d3260035490565b90506000816001600160401b03811115610d4e57610d4e613fed565b604051908082528060200260200182016040528015610da257816020015b6040805160808101825260008082526020820152606091810182905281810191909152815260200190600190039081610d6c5790505b50905060005b82811015610f48576000610dbd600383613820565b90506040518060800160405280826001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3b9190614909565b60ff168152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610e81573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ea9919081019061492c565b8152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610eec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f14919081019061492c565b815250838381518110610f2957610f296149a2565b6020026020010181905250508080610f40906149b8565b915050610da8565b5092915050565b33610f626000546001600160a01b031690565b6001600160a01b031614610f885760405162461bcd60e51b8152600401610a08906149d1565b60008383604051602001610f9d929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b0316610fea5760405162461bcd60e51b8152600401610a08906148b7565b6000818152600f60205260409020600301546001600160a01b03166110515760405162461bcd60e51b815260206004820152601c60248201527f6368616e676520617574686f72697479206e6f7420616c6c6f776564000000006044820152606401610a08565b6001600160a01b03821661106457600080fd5b6000818152600f602090815260409182902060030180546001600160a01b0319166001600160a01b038681169182179092558351878152928301528616917fee5ad7c073e09e589f00215f80efe0e7c6d5b9c4d19f5b85660a348b28ae867f910160405180910390a250505050565b336110e66000546001600160a01b031690565b6001600160a01b03161461110c5760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061111d57504281105b6111395760405162461bcd60e51b8152600401610a0890614a06565b600e80546001600160a01b0319166001600160a01b0384169081179091556040519081527f850b65e0a4a0af8155b0d56212b309166a3618bcd7ba7c1e83f09f3e721f294c906020015b60405180910390a15050565b336111a26000546001600160a01b031690565b6001600160a01b0316146111c85760405162461bcd60e51b8152600401610a08906149d1565b600b5480158015906111d957504281105b6111f55760405162461bcd60e51b8152600401610a0890614a06565b60ff8261120160015490565b61120b9190614a31565b1061124f5760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a08565b60005b8281101561139c57600084848381811061126e5761126e6149a2565b90506020020160208101906112839190614308565b6001600160a01b0316036112a95760405162461bcd60e51b8152600401610a0890614a44565b6112db8484838181106112be576112be6149a2565b90506020020160208101906112d39190614308565b6001906138af565b6113215760405162461bcd60e51b8152602060048201526017602482015276105d5d1a1bdc9a5d1e48185b1c9958591e481859191959604a1b6044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993848483818110611354576113546149a2565b90506020020160208101906113699190614308565b604080516001600160a01b039092168252600160208301520160405180910390a180611394816149b8565b915050611252565b50505050565b60006113ad60015490565b905090565b604080516080810182526000808252602082018190529181018290526060810191909152600f600084846040516020016113ed929190614895565b60408051601f198184030181529181528151602092830120835282820193909352908201600020825160808101845281546001600160a01b03908116825260018301549382019390935260028201548316938101939093526003015416606082015290505b92915050565b600754600160a01b900460ff16156114825760405162461bcd60e51b8152600401610a089061486b565b6001600160a01b0386166114d85760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b60008060006114e8888888613921565b925092509250886001600160a01b0316886001600160a01b0316846001600160a01b03167feaa11317bb61110cf1035a22a7b6b4c716b909b47954d51ee13de1627fdf0f5085858b8b8b604051610d12959493929190614a6a565b600754600160a01b900460ff161561156d5760405162461bcd60e51b8152600401610a089061486b565b6001600160a01b0384166115c35760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420726563656976657220616464726573730000000000006044820152606401610a08565b60008060006115d3868686613921565b925092509250866001600160a01b0316866001600160a01b0316846001600160a01b03167fc9e84ed7aa56cf1771d0373f4b6380ccc9c7cdae154f287abf95c48f72e7f0cf85858960405161163b939291909283526020830191909152604082015260600190565b60405180910390a450505050505050565b6001600160a01b0381166000908152601460205260408120549081900361169d5750506000805260146020527f4f26c3876aa9f4b92579780beea1161a61f87ebf1ec6ee865b299e447ecba99c5490565b80620186a0036116ab575060005b919050565b336116c36000546001600160a01b031690565b6001600160a01b0316146116e95760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b0382166000818152600960205260408082205490516370a0823160e01b8152306004820152919290916370a0823190602401602060405180830381865afa15801561173f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117639190614aa8565b61176d91906148f6565b90506117836001600160a01b038416838361370c565b7f2c5650189f92c7058626efc371b51fe7e71f37dacb696bc7cad0b1320931974a8383836040516117b693929190614ac1565b60405180910390a1505050565b336117d66000546001600160a01b031690565b6001600160a01b0316146117fc5760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b0382166118225760405162461bcd60e51b8152600401610a0890614a44565b6001600160a01b0382166000818152600a6020908152604091829020805460ff19168515159081179091558251938452908301527feabe320fe7911eab2e5125ac393caa5937659b712f0c3ac43316c61d4bc088019101611183565b6000546001600160a01b03163314806118a557503360009081526002602052604090205415155b806118bf5750336000908152600a602052604090205460ff165b6118c857600080fd5b6007805460ff60a01b1916600160a01b179055604051600181527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a1565b336119256000546001600160a01b031690565b6001600160a01b03161461194b5760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061195c57504281105b6119785760405162461bcd60e51b8152600401610a0890614a06565b620186a08211156119ba5760405162461bcd60e51b815260206004820152600c60248201526b546f6f20686967682066656560a01b6044820152606401610a08565b6001600160a01b038316600081815260146020908152604091829020859055815192835282018490527fa065abcf8156e439379371f7924f05c22b16f14de6a1448c5bcbdc525b46dd8591016117b6565b33611a1e6000546001600160a01b031690565b6001600160a01b031614611a445760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590611a5557504281105b611a715760405162461bcd60e51b8152600401610a0890614a06565b6007805460ff60a01b19169055604051600081527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e9060200160405180910390a150565b33611ac86000546001600160a01b031690565b6001600160a01b031614611aee5760405162461bcd60e51b8152600401610a08906149d1565b6001600160a01b038116611b145760405162461bcd60e51b8152600401610a0890614a44565b6040805180820182526001600160a01b038316808252426001600160401b0381166020938401819052600c80546001600160e01b0319168417600160a01b909202919091179055835191825291810182905290917fd990f8f4f90cd3307c50ab3d095cfb65516e999b7584aee60c0af83eb48118de9101611183565b33611ba36000546001600160a01b031690565b6001600160a01b031614611bc95760405162461bcd60e51b8152600401610a08906149d1565b611bd64262015180614a31565b600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611908565b600d546001600160a01b03163314611c655760405162461bcd60e51b815260206004820152601a60248201527f63616c6c6572206973206e6f742074686520666f756e646572730000000000006044820152606401610a08565b6001600160a01b038116611cbb5760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610a08565b600d546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600d80546001600160a01b0319166001600160a01b0392909216919091179055565b33611d2a6000546001600160a01b031690565b6001600160a01b031614611d505760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590611d6157504281105b611d7d5760405162461bcd60e51b8152600401610a0890614a06565b60005b83811015611e58578260126000878785818110611d9f57611d9f6149a2565b9050602002016020810190611db49190614308565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b79287858583818110611e0f57611e0f6149a2565b9050602002016020810190611e249190614308565b604080516001600160a01b03909216825285151560208301520160405180910390a180611e50816149b8565b915050611d80565b5050505050565b468703611ea35760405162461bcd60e51b815260206004820152601260248201527127b7363c903337b932b4b3b7103a37b5b2b760711b6044820152606401610a08565b60008888604051602001611eb8929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b031615611f2c5760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b600089898989898989604051602001611f4b9796959493929190614ae5565b604051602081830303815290604052805190602001209050611f6f60008285613440565b60008787604051602001611f84929190614b36565b604051602081830303815290604052905060008686604051602001611faa929190614b5a565b60408051601f19818403018152919052600654909150600090611fda906001600160a01b03908116908f16613c15565b9050806001600160a01b0316631624f6c684848e6040518463ffffffff1660e01b815260040161200c93929190614b77565b600060405180830381600087803b15801561202657600080fd5b505af115801561203a573d6000803e3d6000fd5b505050508c600f600087815260200190815260200160002060000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508b600f60008781526020019081526020016000206001018190555080600f600087815260200190815260200160002060020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508460106000836001600160a01b03166001600160a01b031681526020019081526020016000208190555061210d8160036138af90919063ffffffff16565b507f7cedf5820723679f9a981ba7249d0ab5c6ecdb2f98392ef5a29051153b9e5a7d818e8e60405161214193929190614ac1565b60405180910390a150505050505050505050505050565b3361216b6000546001600160a01b031690565b6001600160a01b0316146121915760405162461bcd60e51b8152600401610a08906149d1565b600b5480158015906121a257504281105b6121be5760405162461bcd60e51b8152600401610a0890614a06565b82158015906121cf57506001548311155b80156121db5750828211155b6122195760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a08565b601382905560058390556040518381527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf906020016117b6565b606060016000018054806020026020016040519081016040528092919081815260200182805480156122ae57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612290575b5050505050905090565b336122cb6000546001600160a01b031690565b6001600160a01b0316146122f15760405162461bcd60e51b8152600401610a08906149d1565b6000600b8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611908565b6001600160a01b038116600090815260106020526040902054156123845760405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606401610a08565b6000816001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa1580156123c4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123ec919081019061492c565b90506000826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561242e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612456919081019061492c565b90506000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612498573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124bc9190614909565b60ff169050600084466040516020016124d6929190614895565b60408051601f1981840301815291815281516020928301206000818152600f845282812080546001600160a01b038b166001600160a01b03199182168117835546600184015560029092018054909116905581526010909352912081905590506125416003866138af565b50846001600160a01b03167fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c5263468487876040516125819493929190614bb0565b60405180910390a25050505050565b600754600160a01b900460ff16156125ba5760405162461bcd60e51b8152600401610a089061486b565b60008481526008602090815260408083208a845290915290205460ff16156126245760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a08565b60008989604051602001612639929190614895565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091506001600160a01b03166126865760405162461bcd60e51b8152600401610a08906148b7565b60016008600087815260200190815260200160002060008a815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600f600083815260200190815260200160002060030160009054906101000a90046001600160a01b0316905060008b8b8a8a8d8b46308d8d6040516020016127169a99989796959493929190614be1565b604051602081830303815290604052805190602001209050612739828286613440565b50506000818152600f60205260409020600201546001600160a01b0316843b1515801561276f57506001600160a01b0385163014155b1561293e576001600160a01b03811615801561279457506001600160a01b038b166001145b1561280b5750600e54604051631490ba2d60e31b81528b916001600160a01b03169063a485d1689089906127d4908c90869084908c908c90600401614c62565b6000604051808303818588803b1580156127ed57600080fd5b505af1158015612801573d6000803e3d6000fd5b50505050506129f0565b6001600160a01b0381161561288557600e546040516340c10f1960e01b81526001600160a01b03918216600482015260248101899052908216906340c10f1990604401600060405180830381600087803b15801561286857600080fd5b505af115801561287c573d6000803e3d6000fd5b505050506128cf565b506001600160a01b038a16600090815260096020526040812080548c928992916128b09084906148f6565b9091555050600e546128cf906001600160a01b0383811691168961370c565b600e54604051631490ba2d60e31b81526001600160a01b039091169063a485d16890612907908b9085908c908b908b90600401614c62565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b505050506129f0565b6001600160a01b03811615612982576040516340c10f1960e01b81526001600160a01b038981166004830152602482018990528216906340c10f1990604401612907565b50896000196001600160a01b038216016129ae576129a96001600160a01b03891688613643565b6129f0565b6001600160a01b038116600090815260096020526040812080548992906129d69084906148f6565b909155506129f090506001600160a01b038216898961370c565b604080518b8152602081018990529081018a9052606081018790526001600160a01b038681166080830152808a1691838216918e16907f3d5595f71187e446858be0c0fa22a3dd315023362b3b056c5eada14baecfc1019060a00160405180910390a45050505050505050505050565b33612a736000546001600160a01b031690565b6001600160a01b031614612a995760405162461bcd60e51b8152600401610a08906149d1565b60005b81811015612b9d57612ad6838383818110612ab957612ab96149a2565b9050602002016020810190612ace9190614308565b600190613cb5565b612b225760405162461bcd60e51b815260206004820152601860248201527f417574686f7269747920646f6573206e6f7420657869737400000000000000006044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993838383818110612b5557612b556149a2565b9050602002016020810190612b6a9190614308565b604080516001600160a01b039092168252600060208301520160405180910390a180612b95816149b8565b915050612a9c565b505050565b600d546001600160a01b0316331480612bc557506000546001600160a01b031633145b612c1d5760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f742074686520666f756e6460448201526265727360e81b6064820152608401610a08565b6001600160a01b038116612c825760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a08565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b33612cf06000546001600160a01b031690565b6001600160a01b031614612d165760405162461bcd60e51b8152600401610a08906149d1565b600b548015801590612d2757504281105b612d435760405162461bcd60e51b8152600401610a0890614a06565b6001600160a01b038216612d695760405162461bcd60e51b8152600401610a0890614a44565b600780546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca491016117b6565b6001600160a01b03891615801590612de357506001600160a01b03881615155b8015612df857506000546001600160a01b0316155b8015612e0c57506001600160a01b03871615155b612e1557600080fd5b600080546001600160a01b03199081166001600160a01b038c81169182178455600d8054909316908c16179091556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36001600160a01b038616612ec45760405162461bcd60e51b815260206004820152601960248201527f57726f6e6720746f6b656e496d706c656d656e746174696f6e000000000000006044820152606401610a08565b84600003612f065760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a08565b60ff83612f1260015490565b612f1c9190614a31565b10612f605760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a08565b60005b83811015613090576000858583818110612f7f57612f7f6149a2565b9050602002016020810190612f949190614308565b6001600160a01b031603612fba5760405162461bcd60e51b8152600401610a0890614a44565b612fcf8585838181106112be576112be6149a2565b6130155760405162461bcd60e51b8152602060048201526017602482015276105d5d1a1bdc9a5d1e48185b1c9958591e481859191959604a1b6044820152606401610a08565b7f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c361993858583818110613048576130486149a2565b905060200201602081019061305d9190614308565b604080516001600160a01b039092168252600160208301520160405180910390a180613088816149b8565b915050612f63565b50600680546001600160a01b0319166001600160a01b0388161790556040516130b890613fc9565b604051809103906000f0801580156130d4573d6000803e3d6000fd5b50600e80546001600160a01b03199081166001600160a01b0393841617909155600780549091169189169182179055604080516000815260208101929092527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca4910160405180910390a160058590556040518581527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf9060200160405180910390a16001601260008686600081811061318f5761318f6149a2565b90506020020160208101906131a49190614308565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055507f769e5b6d0e1e39e7afbc891ae32dbc689cd164ac034d66bc633096c559b792878484600081811061320f5761320f6149a2565b90506020020160208101906132249190614308565b604080516001600160a01b039092168252600160208301520160405180910390a160016013819055600b819055604051600091613265914690602001614895565b60408051601f1981840301815282825280516020918201206000818152600f835292832080546001600160a01b03191660019081178255469181018290559384905260109092527f8c6065603763fec3f5742441d3833f3f43b982453612d76adb39a885e3006b5f819055935090917fef4ec9b3cfaa22dd32688bf4ac3c820e8b468ffb6452f61717fb9d845f3c52639161330a916012908890889082908290614cc6565b60405180910390a250505050505050505050565b336133316000546001600160a01b031690565b6001600160a01b0316146133575760405162461bcd60e51b8152600401610a08906149d1565b600b54801580159061336857504281105b6133845760405162461bcd60e51b8152600401610a0890614a06565b60005b83811015611e585782601160008787858181106133a6576133a66149a2565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055507f96fb1460e35cd6722dbde21ee5de56c0c1e73920214010e33b2591763744fd8b858583818110613405576134056149a2565b90506020020135846040516134269291909182521515602082015260400190565b60405180910390a180613438816149b8565b915050613387565b613497826040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b915060008080805b84518110156135775760006134cd878784815181106134c0576134c06149a2565b6020026020010151613df7565b6001600160a01b0381166000908152600260205260409020549091506001811b81158015906134fc5750848116155b1561354357938417938561350f816149b8565b6001600160a01b03851660009081526012602052604090205490975060ff16159050613543578661353f816149b8565b9750505b896001600160a01b0316836001600160a01b03160361356157600099505b505050808061356f906149b8565b91505061349f565b508160055411156135ca5760405162461bcd60e51b815260206004820152601760248201527f52657175697265206d6f7265207369676e6174757265730000000000000000006044820152606401610a08565b6001600160a01b0386161580156135e357506013548310155b61363b5760405162461bcd60e51b8152602060048201526024808201527f54686520726571756972656420617574686f726974696573206469646e27742060448201526339b4b3b760e11b6064820152608401610a08565b505050505050565b604080516000808252602082019092526001600160a01b03841690839060405161366d9190614d06565b60006040518083038185875af1925050503d80600081146136aa576040519150601f19603f3d011682016040523d82523d6000602084013e6136af565b606091505b5050905080612b9d5760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610a08565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916137689190614d06565b6000604051808303816000865af19150503d80600081146137a5576040519150601f19603f3d011682016040523d82523d6000602084013e6137aa565b606091505b50915091508180156137d45750805115806137d45750808060200190518101906137d49190614d22565b611e585760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610a08565b8154600090821061387e5760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b6064820152608401610a08565b826000018281548110613893576138936149a2565b6000918252602090912001546001600160a01b03169392505050565b6001600160a01b038116600090815260018301602052604081205461391957508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155611452565b506000611452565b6000818152601160205260408120548190819060ff1680156139435750468414155b61398f5760405162461bcd60e51b815260206004820152601f60248201527f44657374696e6174696f6e20636861696e206e6f7420737570706f72746564006044820152606401610a08565b600061399a8761164c565b90508015613a5857620f42406139b08288614d3f565b6139ba9190614d56565b90506139c681876148f6565b91508015613a53576000196001600160a01b038816016139fb576007546139f6906001600160a01b031682613643565b613a17565b600754613a17906001600160a01b038981169133911684613e76565b7f6ded982279c8387ad8a63e73385031a3807c1862e633f06e09d11bcb6e282f60338883604051613a4a93929190614ac1565b60405180910390a15b613a5c565b8591505b6001600160a01b03871660009081526010602052604081205490819003613aba5760405162461bcd60e51b8152602060048201526012602482015271151bdad95b881dd85cdb89dd08185919195960721b6044820152606401610a08565b6000818152600f6020526040902080546001909101546001600160a01b0391821696509450881660001901613b2c5734871115613b275760405162461bcd60e51b815260206004820152600b60248201526a57726f6e672076616c756560a81b6044820152606401610a08565b613c0a565b6000818152600f60205260409020600201546001600160a01b03808a16911603613bc75760405163079cc67960e41b8152336004820152602481018490526001600160a01b038916906379cc6790906044016020604051808303816000875af1158015613b9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bc19190614d22565b50613c0a565b6001600160a01b03881660009081526009602052604081208054859290613bef908490614a31565b90915550613c0a90506001600160a01b038916333086613e76565b505093509350939050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b0381166114525760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610a08565b6001600160a01b03811660009081526001830160205260408120548015613ded576000613ce36001836148f6565b8554909150600090613cf7906001906148f6565b90506000866000018281548110613d1057613d106149a2565b60009182526020909120015487546001600160a01b0390911691508190889085908110613d3f57613d3f6149a2565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055613d73836001614a31565b6001600160a01b03821660009081526001890160205260409020558654879080613d9f57613d9f614d78565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506114529350505050565b6000915050611452565b600080600080613e0685613f9a565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa158015613e61573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b600080856001600160a01b03166323b872dd868686604051602401613e9d93929190614ac1565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051613ed69190614d06565b6000604051808303816000865af19150503d8060008114613f13576040519150601f19603f3d011682016040523d82523d6000602084013e613f18565b606091505b5091509150818015613f42575080511580613f42575080806020019051810190613f429190614d22565b61363b5760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610a08565b60008060008351604114613fad57600080fd5b5050506020810151604082015160609092015160001a92909190565b610b0680614d8f83390190565b80356001600160a01b03811681146116ab57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561402b5761402b613fed565b604052919050565b60006001600160401b0382111561404c5761404c613fed565b50601f01601f191660200190565b600082601f83011261406b57600080fd5b813561407e61407982614033565b614003565b81815284602083860101111561409357600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f8301126140c157600080fd5b813560206001600160401b03808311156140dd576140dd613fed565b8260051b6140ec838201614003565b938452858101830193838101908886111561410657600080fd5b84880192505b85831015614142578235848111156141245760008081fd5b6141328a87838c010161405a565b835250918401919084019061410c565b98975050505050505050565b600080600080600080600060e0888a03121561416957600080fd5b61417288613fd6565b9650602088013595506040880135945061418e60608901613fd6565b93506080880135925060a0880135915060c08801356001600160401b038111156141b757600080fd5b6141c38a828b016140b0565b91505092959891949750929550565b60005b838110156141ed5781810151838201526020016141d5565b50506000910152565b6000815180845261420e8160208601602086016141d2565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156142be57888303603f19018552815180516001600160a01b031684528781015160ff16888501528681015160808886018190529061428d828701826141f6565b915050606080830151925085820381870152506142aa81836141f6565b968901969450505090860190600101614249565b509098975050505050505050565b6000806000606084860312156142e157600080fd5b6142ea84613fd6565b9250602084013591506142ff60408501613fd6565b90509250925092565b60006020828403121561431a57600080fd5b61432382613fd6565b9392505050565b60008083601f84011261433c57600080fd5b5081356001600160401b0381111561435357600080fd5b6020830191508360208260051b850101111561436e57600080fd5b9250929050565b6000806020838503121561438857600080fd5b82356001600160401b0381111561439e57600080fd5b6143aa8582860161432a565b90969095509350505050565b600080604083850312156143c957600080fd5b6143d283613fd6565b946020939093013593505050565b60008060008060008060c087890312156143f957600080fd5b61440287613fd6565b955061441060208801613fd6565b9450604087013593506060870135925061442c60808801613fd6565b915060a08701356001600160401b0381111561444757600080fd5b61445389828a0161405a565b9150509295509295509295565b6000806000806080858703121561447657600080fd5b61447f85613fd6565b935061448d60208601613fd6565b93969395505050506040820135916060013590565b600080604083850312156144b557600080fd5b6144be83613fd6565b91506144cc60208401613fd6565b90509250929050565b80151581146144e357600080fd5b50565b600080604083850312156144f957600080fd5b61450283613fd6565b91506020830135614512816144d5565b809150509250929050565b60006020828403121561452f57600080fd5b5035919050565b60008060006040848603121561454b57600080fd5b83356001600160401b0381111561456157600080fd5b61456d8682870161432a565b9094509250506020840135614581816144d5565b809150509250925092565b60008083601f84011261459e57600080fd5b5081356001600160401b038111156145b557600080fd5b60208301915083602082850101111561436e57600080fd5b60008060008060008060008060c0898b0312156145e957600080fd5b6145f289613fd6565b9750602089013596506040890135955060608901356001600160401b038082111561461c57600080fd5b6146288c838d0161458c565b909750955060808b013591508082111561464157600080fd5b61464d8c838d0161458c565b909550935060a08b013591508082111561466657600080fd5b506146738b828c016140b0565b9150509295985092959890939650565b6000806040838503121561469657600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156146e65783516001600160a01b0316835292840192918401916001016146c1565b50909695505050505050565b60008060008060008060008060006101208a8c03121561471157600080fd5b61471a8a613fd6565b985060208a0135975060408a0135965061473660608b01613fd6565b955060808a0135945060a08a0135935061475260c08b01613fd6565b925060e08a01356001600160401b038082111561476e57600080fd5b61477a8d838e0161405a565b93506101008c013591508082111561479157600080fd5b5061479e8c828d016140b0565b9150509295985092959850929598565b600080600080600080600080600060e08a8c0312156147cc57600080fd5b6147d58a613fd6565b98506147e360208b01613fd6565b97506147f160408b01613fd6565b96506147ff60608b01613fd6565b955060808a0135945060a08a01356001600160401b038082111561482257600080fd5b61482e8d838e0161432a565b909650945060c08c013591508082111561484757600080fd5b506148548c828d0161458c565b915080935050809150509295985092959850929598565b60208082526010908201526f213934b233b29034b990333937bd32b760811b604082015260600190565b60609290921b6bffffffffffffffffffffffff19168252601482015260340190565b6020808252600f908201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b81810381811115611452576114526148e0565b60006020828403121561491b57600080fd5b815160ff8116811461432357600080fd5b60006020828403121561493e57600080fd5b81516001600160401b0381111561495457600080fd5b8201601f8101841361496557600080fd5b805161497361407982614033565b81815285602083850101111561498857600080fd5b6149998260208301602086016141d2565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016149ca576149ca6148e0565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601190820152704e6f7420696e207365747570206d6f646560781b604082015260600190565b80820180821115611452576114526148e0565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b85815284602082015283604082015260018060a01b038316606082015260a060808201526000614a9d60a08301846141f6565b979650505050505050565b600060208284031215614aba57600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6bffffffffffffffffffffffff198860601b16815286601482015285603482015283856054830137600084820160548101600081528486823750600093016054019283525090979650505050505050565b6702bb930b83832b2160c51b81528183600883013760009101600801908152919050565b605760f81b81528183600183013760009101600101908152919050565b606081526000614b8a60608301866141f6565b8281036020840152614b9c81866141f6565b91505060ff83166040830152949350505050565b848152836020820152608060408201526000614bcf60808301856141f6565b8281036060840152614a9d81856141f6565b60006bffffffffffffffffffffffff19808d60601b1683528b6014840152808b60601b1660348401528960488401528860688401528760888401528660a8840152808660601b1660c8840152808560601b1660dc840152508251614c4c8160f08501602087016141d2565b9190910160f0019b9a5050505050505050505050565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a060808201819052600090614a9d908301846141f6565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b868152856020820152608060408201526000614ce6608083018688614c9d565b8281036060840152614cf9818587614c9d565b9998505050505050505050565b60008251614d188184602087016141d2565b9190910192915050565b600060208284031215614d3457600080fd5b8151614323816144d5565b8082028115828204841417611452576114526148e0565b600082614d7357634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fdfe608060405234801561001057600080fd5b50600080546001600160a01b03191633179055610ad4806100326000396000f3fe60806040526004361061003f5760003560e01c80635431c94e146100445780638943ec0214610066578063a485d16814610086578063e78cea9214610099575b600080fd5b34801561005057600080fd5b5061006461005f36600461081e565b6100d5565b005b34801561007257600080fd5b50610064610081366004610857565b610294565b6100646100943660046108f6565b6102ea565b3480156100a557600080fd5b506000546100b9906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b60008054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014a91906109e9565b6001600160a01b0316336001600160a01b03161461019c5760405162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b60448201526064015b60405180910390fd5b60006001600160a01b0383166101c65750476101c16001600160a01b03831682610510565b610244565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561020a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022e9190610a0d565b90506102446001600160a01b03841683836105de565b604080516001600160a01b038086168252841660208201529081018290527f0f51b71e5e9ee881072b57bf4022b60435e0000ad377b5c1434da39471002b559060600160405180910390a1505050565b6000546001600160a01b038581169116146102e45760405162461bcd60e51b815260206004820152601060248201526f4f6e6c792066726f6d2062726964676560801b6044820152606401610193565b50505050565b6000546001600160a01b031633146103325760405162461bcd60e51b815260206004820152600b60248201526a4f6e6c792062726964676560a81b6044820152606401610193565b6000196001600160a01b038516016103e95734925060006103538447610a26565b90506000836001600160a01b031685846040516103709190610a4d565b60006040518083038185875af1925050503d80600081146103ad576040519150601f19603f3d011682016040523d82523d6000602084013e6103b2565b606091505b5050905080156103c9576103c68247610a26565b94505b84156103e2576103e26001600160a01b03881686610510565b5050610509565b6103fd6001600160a01b03851683856106f2565b6000826001600160a01b03166000836040516104199190610a4d565b60006040518083038185875af1925050503d8060008114610456576040519150601f19603f3d011682016040523d82523d6000602084013e61045b565b606091505b5050905080156104d857604051636eb1769f60e11b81523060048201526001600160a01b03848116602483015286169063dd62ed3e90604401602060405180830381865afa1580156104b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d59190610a0d565b93505b8315610507576104f36001600160a01b0386168460006106f2565b6105076001600160a01b03861687866105de565b505b5050505050565b604080516000808252602082019092526001600160a01b03841690839060405161053a9190610a4d565b60006040518083038185875af1925050503d8060008114610577576040519150601f19603f3d011682016040523d82523d6000602084013e61057c565b606091505b50509050806105d95760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610193565b505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161063a9190610a4d565b6000604051808303816000865af19150503d8060008114610677576040519150601f19603f3d011682016040523d82523d6000602084013e61067c565b606091505b50915091508180156106a65750805115806106a65750808060200190518101906106a69190610a7c565b6105095760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610193565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b179052915160009283929087169161074e9190610a4d565b6000604051808303816000865af19150503d806000811461078b576040519150601f19603f3d011682016040523d82523d6000602084013e610790565b606091505b50915091508180156107ba5750805115806107ba5750808060200190518101906107ba9190610a7c565b6105095760405162461bcd60e51b815260206004820152601e60248201527f5472616e7366657248656c7065723a20415050524f56455f4641494c454400006044820152606401610193565b6001600160a01b038116811461081b57600080fd5b50565b6000806040838503121561083157600080fd5b823561083c81610806565b9150602083013561084c81610806565b809150509250929050565b6000806000806060858703121561086d57600080fd5b843561087881610806565b935060208501359250604085013567ffffffffffffffff8082111561089c57600080fd5b818701915087601f8301126108b057600080fd5b8135818111156108bf57600080fd5b8860208285010111156108d157600080fd5b95989497505060200194505050565b634e487b7160e01b600052604160045260246000fd5b600080600080600060a0868803121561090e57600080fd5b853561091981610806565b9450602086013561092981610806565b935060408601359250606086013561094081610806565b9150608086013567ffffffffffffffff8082111561095d57600080fd5b818801915088601f83011261097157600080fd5b813581811115610983576109836108e0565b604051601f8201601f19908116603f011681019083821181831017156109ab576109ab6108e0565b816040528281528b60208487010111156109c457600080fd5b8260208601602083013760006020848301015280955050505050509295509295909350565b6000602082840312156109fb57600080fd5b8151610a0681610806565b9392505050565b600060208284031215610a1f57600080fd5b5051919050565b81810381811115610a4757634e487b7160e01b600052601160045260246000fd5b92915050565b6000825160005b81811015610a6e5760208186018101518583015201610a54565b506000920191825250919050565b600060208284031215610a8e57600080fd5b81518015158114610a0657600080fdfea26469706673582212208afe667ddb88db78c3484d988496ed61ef38a3f5b7fcea15a41c39ac1c0b566e64736f6c63430008130033a264697066735822122089a9415157d8f781cf8ced25f5811663759b67f6eabcfaff6a1c203a5fa516eb64736f6c63430008130033