Contract Address Details

0x9B36f165baB9ebe611d491180418d8De4b8f3a1f

Contract Name
PeggedTokenBridgeV2
Creator
0x58b529–b7bbc1 at 0x0b8b6a–ac2c57
Balance
0 REI ( )
Tokens
Fetching tokens...
Transactions
134 Transactions
Transfers
0 Transfers
Gas Used
10,787,370
Last Balance Update
20105100
Contract name:
PeggedTokenBridgeV2




Optimization enabled
true
Compiler version
v0.8.9+commit.e5eed63a




Optimization runs
800
Verified at
2022-12-01T07:21:32.183647Z

Constructor Arguments

000000000000000000000000841ce48f9446c8e281d3f1444cb859b4a6d0738c

Arg [0] (address) : 0x841ce48f9446c8e281d3f1444cb859b4a6d0738c

              

Contract source code

// Sources flattened with hardhat v2.9.0 https://hardhat.org

// File contracts/interfaces/ISigsVerifier.sol

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity 0.8.9;

interface ISigsVerifier {
    /**
     * @notice Verifies that a message is signed by a quorum among the signers.
     * @param _msg signed message
     * @param _sigs list of signatures sorted by signer addresses in ascending order
     * @param _signers sorted list of current signers
     * @param _powers powers of current signers
     */
    function verifySigs(
        bytes memory _msg,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external view;
}


// File contracts/interfaces/IPeggedToken.sol

interface IPeggedToken {
    function mint(address _to, uint256 _amount) external;

    function burn(address _from, uint256 _amount) external;
}


// File contracts/interfaces/IPeggedTokenBurnFrom.sol

// used for pegged token with openzeppelin ERC20Burnable interface
// only compatible with PeggedTokenBridgeV2
interface IPeggedTokenBurnFrom {
    function mint(address _to, uint256 _amount) external;

    function burnFrom(address _from, uint256 _amount) external;
}


// File contracts/libraries/Pb.sol

// runtime proto sol library
library Pb {
    enum WireType {
        Varint,
        Fixed64,
        LengthDelim,
        StartGroup,
        EndGroup,
        Fixed32
    }

    struct Buffer {
        uint256 idx; // the start index of next read. when idx=b.length, we're done
        bytes b; // hold serialized proto msg, readonly
    }

    // create a new in-memory Buffer object from raw msg bytes
    function fromBytes(bytes memory raw) internal pure returns (Buffer memory buf) {
        buf.b = raw;
        buf.idx = 0;
    }

    // whether there are unread bytes
    function hasMore(Buffer memory buf) internal pure returns (bool) {
        return buf.idx < buf.b.length;
    }

    // decode current field number and wiretype
    function decKey(Buffer memory buf) internal pure returns (uint256 tag, WireType wiretype) {
        uint256 v = decVarint(buf);
        tag = v / 8;
        wiretype = WireType(v & 7);
    }

    // count tag occurrences, return an array due to no memory map support
    // have to create array for (maxtag+1) size. cnts[tag] = occurrences
    // should keep buf.idx unchanged because this is only a count function
    function cntTags(Buffer memory buf, uint256 maxtag) internal pure returns (uint256[] memory cnts) {
        uint256 originalIdx = buf.idx;
        cnts = new uint256[](maxtag + 1); // protobuf's tags are from 1 rather than 0
        uint256 tag;
        WireType wire;
        while (hasMore(buf)) {
            (tag, wire) = decKey(buf);
            cnts[tag] += 1;
            skipValue(buf, wire);
        }
        buf.idx = originalIdx;
    }

    // read varint from current buf idx, move buf.idx to next read, return the int value
    function decVarint(Buffer memory buf) internal pure returns (uint256 v) {
        bytes10 tmp; // proto int is at most 10 bytes (7 bits can be used per byte)
        bytes memory bb = buf.b; // get buf.b mem addr to use in assembly
        v = buf.idx; // use v to save one additional uint variable
        assembly {
            tmp := mload(add(add(bb, 32), v)) // load 10 bytes from buf.b[buf.idx] to tmp
        }
        uint256 b; // store current byte content
        v = 0; // reset to 0 for return value
        for (uint256 i = 0; i < 10; i++) {
            assembly {
                b := byte(i, tmp) // don't use tmp[i] because it does bound check and costs extra
            }
            v |= (b & 0x7F) << (i * 7);
            if (b & 0x80 == 0) {
                buf.idx += i + 1;
                return v;
            }
        }
        revert(); // i=10, invalid varint stream
    }

    // read length delimited field and return bytes
    function decBytes(Buffer memory buf) internal pure returns (bytes memory b) {
        uint256 len = decVarint(buf);
        uint256 end = buf.idx + len;
        require(end <= buf.b.length); // avoid overflow
        b = new bytes(len);
        bytes memory bufB = buf.b; // get buf.b mem addr to use in assembly
        uint256 bStart;
        uint256 bufBStart = buf.idx;
        assembly {
            bStart := add(b, 32)
            bufBStart := add(add(bufB, 32), bufBStart)
        }
        for (uint256 i = 0; i < len; i += 32) {
            assembly {
                mstore(add(bStart, i), mload(add(bufBStart, i)))
            }
        }
        buf.idx = end;
    }

    // return packed ints
    function decPacked(Buffer memory buf) internal pure returns (uint256[] memory t) {
        uint256 len = decVarint(buf);
        uint256 end = buf.idx + len;
        require(end <= buf.b.length); // avoid overflow
        // array in memory must be init w/ known length
        // so we have to create a tmp array w/ max possible len first
        uint256[] memory tmp = new uint256[](len);
        uint256 i = 0; // count how many ints are there
        while (buf.idx < end) {
            tmp[i] = decVarint(buf);
            i++;
        }
        t = new uint256[](i); // init t with correct length
        for (uint256 j = 0; j < i; j++) {
            t[j] = tmp[j];
        }
        return t;
    }

    // move idx pass current value field, to beginning of next tag or msg end
    function skipValue(Buffer memory buf, WireType wire) internal pure {
        if (wire == WireType.Varint) {
            decVarint(buf);
        } else if (wire == WireType.LengthDelim) {
            uint256 len = decVarint(buf);
            buf.idx += len; // skip len bytes value data
            require(buf.idx <= buf.b.length); // avoid overflow
        } else {
            revert();
        } // unsupported wiretype
    }

    // type conversion help utils
    function _bool(uint256 x) internal pure returns (bool v) {
        return x != 0;
    }

    function _uint256(bytes memory b) internal pure returns (uint256 v) {
        require(b.length <= 32); // b's length must be smaller than or equal to 32
        assembly {
            v := mload(add(b, 32))
        } // load all 32bytes to v
        v = v >> (8 * (32 - b.length)); // only first b.length is valid
    }

    function _address(bytes memory b) internal pure returns (address v) {
        v = _addressPayable(b);
    }

    function _addressPayable(bytes memory b) internal pure returns (address payable v) {
        require(b.length == 20);
        //load 32bytes then shift right 12 bytes
        assembly {
            v := div(mload(add(b, 32)), 0x1000000000000000000000000)
        }
    }

    function _bytes32(bytes memory b) internal pure returns (bytes32 v) {
        require(b.length == 32);
        assembly {
            v := mload(add(b, 32))
        }
    }

    // uint[] to uint8[]
    function uint8s(uint256[] memory arr) internal pure returns (uint8[] memory t) {
        t = new uint8[](arr.length);
        for (uint256 i = 0; i < t.length; i++) {
            t[i] = uint8(arr[i]);
        }
    }

    function uint32s(uint256[] memory arr) internal pure returns (uint32[] memory t) {
        t = new uint32[](arr.length);
        for (uint256 i = 0; i < t.length; i++) {
            t[i] = uint32(arr[i]);
        }
    }

    function uint64s(uint256[] memory arr) internal pure returns (uint64[] memory t) {
        t = new uint64[](arr.length);
        for (uint256 i = 0; i < t.length; i++) {
            t[i] = uint64(arr[i]);
        }
    }

    function bools(uint256[] memory arr) internal pure returns (bool[] memory t) {
        t = new bool[](arr.length);
        for (uint256 i = 0; i < t.length; i++) {
            t[i] = arr[i] != 0;
        }
    }
}


// File contracts/libraries/PbPegged.sol

// Code generated by protoc-gen-sol. DO NOT EDIT.
// source: contracts/libraries/proto/pegged.proto

library PbPegged {
    using Pb for Pb.Buffer; // so we can call Pb funcs on Buffer obj

    struct Mint {
        address token; // tag: 1
        address account; // tag: 2
        uint256 amount; // tag: 3
        address depositor; // tag: 4
        uint64 refChainId; // tag: 5
        bytes32 refId; // tag: 6
    } // end struct Mint

    function decMint(bytes memory raw) internal pure returns (Mint memory m) {
        Pb.Buffer memory buf = Pb.fromBytes(raw);

        uint256 tag;
        Pb.WireType wire;
        while (buf.hasMore()) {
            (tag, wire) = buf.decKey();
            if (false) {}
            // solidity has no switch/case
            else if (tag == 1) {
                m.token = Pb._address(buf.decBytes());
            } else if (tag == 2) {
                m.account = Pb._address(buf.decBytes());
            } else if (tag == 3) {
                m.amount = Pb._uint256(buf.decBytes());
            } else if (tag == 4) {
                m.depositor = Pb._address(buf.decBytes());
            } else if (tag == 5) {
                m.refChainId = uint64(buf.decVarint());
            } else if (tag == 6) {
                m.refId = Pb._bytes32(buf.decBytes());
            } else {
                buf.skipValue(wire);
            } // skip value of unknown tag
        }
    } // end decoder Mint

    struct Withdraw {
        address token; // tag: 1
        address receiver; // tag: 2
        uint256 amount; // tag: 3
        address burnAccount; // tag: 4
        uint64 refChainId; // tag: 5
        bytes32 refId; // tag: 6
    } // end struct Withdraw

    function decWithdraw(bytes memory raw) internal pure returns (Withdraw memory m) {
        Pb.Buffer memory buf = Pb.fromBytes(raw);

        uint256 tag;
        Pb.WireType wire;
        while (buf.hasMore()) {
            (tag, wire) = buf.decKey();
            if (false) {}
            // solidity has no switch/case
            else if (tag == 1) {
                m.token = Pb._address(buf.decBytes());
            } else if (tag == 2) {
                m.receiver = Pb._address(buf.decBytes());
            } else if (tag == 3) {
                m.amount = Pb._uint256(buf.decBytes());
            } else if (tag == 4) {
                m.burnAccount = Pb._address(buf.decBytes());
            } else if (tag == 5) {
                m.refChainId = uint64(buf.decVarint());
            } else if (tag == 6) {
                m.refId = Pb._bytes32(buf.decBytes());
            } else {
                buf.skipValue(wire);
            } // skip value of unknown tag
        }
    } // end decoder Withdraw
}


// File @openzeppelin/contracts/utils/[email protected]

// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}


// File @openzeppelin/contracts/access/[email protected]

// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @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() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}


// File @openzeppelin/contracts/security/[email protected]

// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}


// File contracts/safeguard/Pauser.sol


abstract contract Pauser is Ownable, Pausable {
    mapping(address => bool) public pausers;

    event PauserAdded(address account);
    event PauserRemoved(address account);

    constructor() {
        _addPauser(msg.sender);
    }

    modifier onlyPauser() {
        require(isPauser(msg.sender), "Caller is not pauser");
        _;
    }

    function pause() public onlyPauser {
        _pause();
    }

    function unpause() public onlyPauser {
        _unpause();
    }

    function isPauser(address account) public view returns (bool) {
        return pausers[account];
    }

    function addPauser(address account) public onlyOwner {
        _addPauser(account);
    }

    function removePauser(address account) public onlyOwner {
        _removePauser(account);
    }

    function renouncePauser() public {
        _removePauser(msg.sender);
    }

    function _addPauser(address account) private {
        require(!isPauser(account), "Account is already pauser");
        pausers[account] = true;
        emit PauserAdded(account);
    }

    function _removePauser(address account) private {
        require(isPauser(account), "Account is not pauser");
        pausers[account] = false;
        emit PauserRemoved(account);
    }
}


// File contracts/safeguard/Governor.sol

abstract contract Governor is Ownable {
    mapping(address => bool) public governors;

    event GovernorAdded(address account);
    event GovernorRemoved(address account);

    modifier onlyGovernor() {
        require(isGovernor(msg.sender), "Caller is not governor");
        _;
    }

    constructor() {
        _addGovernor(msg.sender);
    }

    function isGovernor(address _account) public view returns (bool) {
        return governors[_account];
    }

    function addGovernor(address _account) public onlyOwner {
        _addGovernor(_account);
    }

    function removeGovernor(address _account) public onlyOwner {
        _removeGovernor(_account);
    }

    function renounceGovernor() public {
        _removeGovernor(msg.sender);
    }

    function _addGovernor(address _account) private {
        require(!isGovernor(_account), "Account is already governor");
        governors[_account] = true;
        emit GovernorAdded(_account);
    }

    function _removeGovernor(address _account) private {
        require(isGovernor(_account), "Account is not governor");
        governors[_account] = false;
        emit GovernorRemoved(_account);
    }
}


// File contracts/safeguard/VolumeControl.sol

abstract contract VolumeControl is Governor {
    uint256 public epochLength; // seconds
    mapping(address => uint256) public epochVolumes; // key is token
    mapping(address => uint256) public epochVolumeCaps; // key is token
    mapping(address => uint256) public lastOpTimestamps; // key is token

    event EpochLengthUpdated(uint256 length);
    event EpochVolumeUpdated(address token, uint256 cap);

    function setEpochLength(uint256 _length) external onlyGovernor {
        epochLength = _length;
        emit EpochLengthUpdated(_length);
    }

    function setEpochVolumeCaps(address[] calldata _tokens, uint256[] calldata _caps) external onlyGovernor {
        require(_tokens.length == _caps.length, "length mismatch");
        for (uint256 i = 0; i < _tokens.length; i++) {
            epochVolumeCaps[_tokens[i]] = _caps[i];
            emit EpochVolumeUpdated(_tokens[i], _caps[i]);
        }
    }

    function _updateVolume(address _token, uint256 _amount) internal {
        if (epochLength == 0) {
            return;
        }
        uint256 cap = epochVolumeCaps[_token];
        if (cap == 0) {
            return;
        }
        uint256 volume = epochVolumes[_token];
        uint256 timestamp = block.timestamp;
        uint256 epochStartTime = (timestamp / epochLength) * epochLength;
        if (lastOpTimestamps[_token] < epochStartTime) {
            volume = _amount;
        } else {
            volume += _amount;
        }
        require(volume <= cap, "volume exceeds cap");
        epochVolumes[_token] = volume;
        lastOpTimestamps[_token] = timestamp;
    }
}


// File contracts/safeguard/DelayedTransfer.sol

abstract contract DelayedTransfer is Governor {
    struct delayedTransfer {
        address receiver;
        address token;
        uint256 amount;
        uint256 timestamp;
    }
    mapping(bytes32 => delayedTransfer) public delayedTransfers;
    mapping(address => uint256) public delayThresholds;
    uint256 public delayPeriod; // in seconds

    event DelayedTransferAdded(bytes32 id);
    event DelayedTransferExecuted(bytes32 id, address receiver, address token, uint256 amount);

    event DelayPeriodUpdated(uint256 period);
    event DelayThresholdUpdated(address token, uint256 threshold);

    function setDelayThresholds(address[] calldata _tokens, uint256[] calldata _thresholds) external onlyGovernor {
        require(_tokens.length == _thresholds.length, "length mismatch");
        for (uint256 i = 0; i < _tokens.length; i++) {
            delayThresholds[_tokens[i]] = _thresholds[i];
            emit DelayThresholdUpdated(_tokens[i], _thresholds[i]);
        }
    }

    function setDelayPeriod(uint256 _period) external onlyGovernor {
        delayPeriod = _period;
        emit DelayPeriodUpdated(_period);
    }

    function _addDelayedTransfer(
        bytes32 id,
        address receiver,
        address token,
        uint256 amount
    ) internal {
        require(delayedTransfers[id].timestamp == 0, "delayed transfer already exists");
        delayedTransfers[id] = delayedTransfer({
            receiver: receiver,
            token: token,
            amount: amount,
            timestamp: block.timestamp
        });
        emit DelayedTransferAdded(id);
    }

    // caller needs to do the actual token transfer
    function _executeDelayedTransfer(bytes32 id) internal returns (delayedTransfer memory) {
        delayedTransfer memory transfer = delayedTransfers[id];
        require(transfer.timestamp > 0, "delayed transfer not exist");
        require(block.timestamp > transfer.timestamp + delayPeriod, "delayed transfer still locked");
        delete delayedTransfers[id];
        emit DelayedTransferExecuted(id, transfer.receiver, transfer.token, transfer.amount);
        return transfer;
    }
}


// File contracts/pegged-bridge/PeggedTokenBridgeV2.sol







/**
 * @title The bridge contract to mint and burn pegged tokens
 * @dev Work together with OriginalTokenVault deployed at remote chains.
 */
contract PeggedTokenBridgeV2 is Pauser, VolumeControl, DelayedTransfer {
    ISigsVerifier public immutable sigsVerifier;

    mapping(bytes32 => bool) public records;

    mapping(address => uint256) public minBurn;
    mapping(address => uint256) public maxBurn;

    event Mint(
        bytes32 mintId,
        address token,
        address account,
        uint256 amount,
        // ref_chain_id defines the reference chain ID, taking values of:
        // 1. The common case: the chain ID on which the remote corresponding deposit or burn happened;
        // 2. Refund for wrong burn: this chain ID on which the burn happened
        uint64 refChainId,
        // ref_id defines a unique reference ID, taking values of:
        // 1. The common case of deposit/burn-mint: the deposit or burn ID on the remote chain;
        // 2. Refund for wrong burn: the burn ID on this chain
        bytes32 refId,
        address depositor
    );
    event Burn(
        bytes32 burnId,
        address token,
        address account,
        uint256 amount,
        uint64 toChainId,
        address toAccount,
        uint64 nonce
    );
    event MinBurnUpdated(address token, uint256 amount);
    event MaxBurnUpdated(address token, uint256 amount);

    constructor(ISigsVerifier _sigsVerifier) {
        sigsVerifier = _sigsVerifier;
    }

    /**
     * @notice Mint tokens triggered by deposit at a remote chain's OriginalTokenVault.
     * @param _request The serialized Mint protobuf.
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by
     * +2/3 of the sigsVerifier's current signing power to be delivered.
     * @param _signers The sorted list of signers.
     * @param _powers The signing powers of the signers.
     */
    function mint(
        bytes calldata _request,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external whenNotPaused returns (bytes32) {
        bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "Mint"));
        sigsVerifier.verifySigs(abi.encodePacked(domain, _request), _sigs, _signers, _powers);
        PbPegged.Mint memory request = PbPegged.decMint(_request);
        bytes32 mintId = keccak256(
            // len = 20 + 20 + 32 + 20 + 8 + 32 + 20 = 152
            abi.encodePacked(
                request.account,
                request.token,
                request.amount,
                request.depositor,
                request.refChainId,
                request.refId,
                address(this)
            )
        );
        require(records[mintId] == false, "record exists");
        records[mintId] = true;
        _updateVolume(request.token, request.amount);
        uint256 delayThreshold = delayThresholds[request.token];
        if (delayThreshold > 0 && request.amount > delayThreshold) {
            _addDelayedTransfer(mintId, request.account, request.token, request.amount);
        } else {
            IPeggedToken(request.token).mint(request.account, request.amount);
        }
        emit Mint(
            mintId,
            request.token,
            request.account,
            request.amount,
            request.refChainId,
            request.refId,
            request.depositor
        );
        return mintId;
    }

    /**
     * @notice Burn pegged tokens to trigger a cross-chain withdrawal of the original tokens at a remote chain's
     * OriginalTokenVault, or mint at another remote chain
     * NOTE: This function DOES NOT SUPPORT fee-on-transfer / rebasing tokens.
     * @param _token The pegged token address.
     * @param _amount The amount to burn.
     * @param _toChainId If zero, withdraw from original vault; otherwise, the remote chain to mint tokens.
     * @param _toAccount The account to receive tokens on the remote chain
     * @param _nonce A number to guarantee unique depositId. Can be timestamp in practice.
     */
    function burn(
        address _token,
        uint256 _amount,
        uint64 _toChainId,
        address _toAccount,
        uint64 _nonce
    ) external whenNotPaused returns (bytes32) {
        bytes32 burnId = _burn(_token, _amount, _toChainId, _toAccount, _nonce);
        IPeggedToken(_token).burn(msg.sender, _amount);
        return burnId;
    }

    // same with `burn` above, use openzeppelin ERC20Burnable interface
    function burnFrom(
        address _token,
        uint256 _amount,
        uint64 _toChainId,
        address _toAccount,
        uint64 _nonce
    ) external whenNotPaused returns (bytes32) {
        bytes32 burnId = _burn(_token, _amount, _toChainId, _toAccount, _nonce);
        IPeggedTokenBurnFrom(_token).burnFrom(msg.sender, _amount);
        return burnId;
    }

    function _burn(
        address _token,
        uint256 _amount,
        uint64 _toChainId,
        address _toAccount,
        uint64 _nonce
    ) private returns (bytes32) {
        require(_amount > minBurn[_token], "amount too small");
        require(maxBurn[_token] == 0 || _amount <= maxBurn[_token], "amount too large");
        bytes32 burnId = keccak256(
            // len = 20 + 20 + 32 + 8 + 20 + 8 + 8 + 20 = 136
            abi.encodePacked(
                msg.sender,
                _token,
                _amount,
                _toChainId,
                _toAccount,
                _nonce,
                uint64(block.chainid),
                address(this)
            )
        );
        require(records[burnId] == false, "record exists");
        records[burnId] = true;
        emit Burn(burnId, _token, msg.sender, _amount, _toChainId, _toAccount, _nonce);
        return burnId;
    }

    function executeDelayedTransfer(bytes32 id) external whenNotPaused {
        delayedTransfer memory transfer = _executeDelayedTransfer(id);
        IPeggedToken(transfer.token).mint(transfer.receiver, transfer.amount);
    }

    function setMinBurn(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
        require(_tokens.length == _amounts.length, "length mismatch");
        for (uint256 i = 0; i < _tokens.length; i++) {
            minBurn[_tokens[i]] = _amounts[i];
            emit MinBurnUpdated(_tokens[i], _amounts[i]);
        }
    }

    function setMaxBurn(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
        require(_tokens.length == _amounts.length, "length mismatch");
        for (uint256 i = 0; i < _tokens.length; i++) {
            maxBurn[_tokens[i]] = _amounts[i];
            emit MaxBurnUpdated(_tokens[i], _amounts[i]);
        }
    }
}
        
>

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_sigsVerifier","internalType":"contract ISigsVerifier"}]},{"type":"event","name":"Burn","inputs":[{"type":"bytes32","name":"burnId","internalType":"bytes32","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint64","name":"toChainId","internalType":"uint64","indexed":false},{"type":"address","name":"toAccount","internalType":"address","indexed":false},{"type":"uint64","name":"nonce","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"DelayPeriodUpdated","inputs":[{"type":"uint256","name":"period","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DelayThresholdUpdated","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"threshold","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DelayedTransferAdded","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"DelayedTransferExecuted","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32","indexed":false},{"type":"address","name":"receiver","internalType":"address","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EpochLengthUpdated","inputs":[{"type":"uint256","name":"length","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EpochVolumeUpdated","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"cap","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GovernorAdded","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"GovernorRemoved","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"MaxBurnUpdated","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MinBurnUpdated","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Mint","inputs":[{"type":"bytes32","name":"mintId","internalType":"bytes32","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint64","name":"refChainId","internalType":"uint64","indexed":false},{"type":"bytes32","name":"refId","internalType":"bytes32","indexed":false},{"type":"address","name":"depositor","internalType":"address","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":"Paused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"PauserAdded","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"PauserRemoved","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addGovernor","inputs":[{"type":"address","name":"_account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addPauser","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"burn","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"uint64","name":"_toChainId","internalType":"uint64"},{"type":"address","name":"_toAccount","internalType":"address"},{"type":"uint64","name":"_nonce","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"burnFrom","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"uint64","name":"_toChainId","internalType":"uint64"},{"type":"address","name":"_toAccount","internalType":"address"},{"type":"uint64","name":"_nonce","internalType":"uint64"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"delayPeriod","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"delayThresholds","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"delayedTransfers","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"epochLength","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"epochVolumeCaps","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"epochVolumes","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeDelayedTransfer","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"governors","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isGovernor","inputs":[{"type":"address","name":"_account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isPauser","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastOpTimestamps","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxBurn","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minBurn","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"mint","inputs":[{"type":"bytes","name":"_request","internalType":"bytes"},{"type":"bytes[]","name":"_sigs","internalType":"bytes[]"},{"type":"address[]","name":"_signers","internalType":"address[]"},{"type":"uint256[]","name":"_powers","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"pausers","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"records","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeGovernor","inputs":[{"type":"address","name":"_account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removePauser","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceGovernor","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renouncePauser","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDelayPeriod","inputs":[{"type":"uint256","name":"_period","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDelayThresholds","inputs":[{"type":"address[]","name":"_tokens","internalType":"address[]"},{"type":"uint256[]","name":"_thresholds","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setEpochLength","inputs":[{"type":"uint256","name":"_length","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setEpochVolumeCaps","inputs":[{"type":"address[]","name":"_tokens","internalType":"address[]"},{"type":"uint256[]","name":"_caps","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxBurn","inputs":[{"type":"address[]","name":"_tokens","internalType":"address[]"},{"type":"uint256[]","name":"_amounts","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinBurn","inputs":[{"type":"address[]","name":"_tokens","internalType":"address[]"},{"type":"uint256[]","name":"_amounts","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ISigsVerifier"}],"name":"sigsVerifier","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unpause","inputs":[]}]
              

Contract Creation Code

0x60a06040523480156200001157600080fd5b5060405162002ec538038062002ec583398101604081905262000034916200024f565b6200003f3362000074565b6000805460ff60a01b191690556200005733620000c4565b62000062336200018f565b6001600160a01b031660805262000281565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811660009081526001602052604090205460ff1615620001335760405162461bcd60e51b815260206004820152601960248201527f4163636f756e7420697320616c7265616479207061757365720000000000000060448201526064015b60405180910390fd5b6001600160a01b038116600081815260016020818152604092839020805460ff191690921790915590519182527f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f891015b60405180910390a150565b6001600160a01b03811660009081526002602052604090205460ff1615620001fa5760405162461bcd60e51b815260206004820152601b60248201527f4163636f756e7420697320616c726561647920676f7665726e6f72000000000060448201526064016200012a565b6001600160a01b038116600081815260026020908152604091829020805460ff1916600117905590519182527fdc5a48d79e2e147530ff63ecdbed5a5a66adb9d5cf339384d5d076da197c40b5910162000184565b6000602082840312156200026257600080fd5b81516001600160a01b03811681146200027a57600080fd5b9392505050565b608051612c21620002a46000396000818161055f01526112bb0152612c216000f3fe608060405234801561001057600080fd5b50600436106102775760003560e01c806382dc1ec411610160578063bf4816f0116100d8578063eecdac881161008c578063f832138311610071578063f8321383146105fe578063f87343021461061e578063f9a8ea081461063157600080fd5b8063eecdac88146105d8578063f2fde38b146105eb57600080fd5b8063e026049c116100bd578063e026049c14610581578063e3eece2614610589578063e43581b8146105ac57600080fd5b8063bf4816f014610547578063ccf2683b1461055a57600080fd5b80639e422c331161012f578063adc0d57f11610114578063adc0d57f146104b1578063b1c94d941461051e578063b5f2bc471461052757600080fd5b80639e422c331461048b578063a00293011461049e57600080fd5b806382dc1ec4146104385780638456cb591461044b5780638da5cb5b146104535780639e25fc5c1461047857600080fd5b806354eea796116101f35780636b2c0f55116101c2578063715018a6116101a7578063715018a6146103ed5780637f856013146103f557806380f51c121461041557600080fd5b80636b2c0f55146103d25780636ef8d66d146103e557600080fd5b806354eea7961461038457806357d775f8146103975780635c975abb146103a057806360216b00146103b257600080fd5b80633f4ba83a1161024a57806347b16c6c1161022f57806347b16c6c14610323578063497bf3b21461033657806352532faa1461036457600080fd5b80633f4ba83a146102ef57806346fbf68e146102f757600080fd5b806301e647251461027c57806317bdbae5146102b45780633c4a25d0146102c95780633d572107146102dc575b600080fd5b61029f61028a366004612691565b600a6020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6102c76102c23660046126f6565b610644565b005b6102c76102d736600461277e565b6107e7565b6102c76102ea366004612691565b61084d565b6102c76108e1565b61029f61030536600461277e565b6001600160a01b031660009081526001602052604090205460ff1690565b6102c76103313660046126f6565b61094a565b61035661034436600461277e565b600c6020526000908152604090205481565b6040519081526020016102ab565b61035661037236600461277e565b60086020526000908152604090205481565b6102c7610392366004612691565b610ae1565b61035660035481565b600054600160a01b900460ff1661029f565b6103566103c036600461277e565b60046020526000908152604090205481565b6102c76103e036600461277e565b610b6e565b6102c7610bd1565b6102c7610bda565b61035661040336600461277e565b600b6020526000908152604090205481565b61029f61042336600461277e565b60016020526000908152604090205460ff1681565b6102c761044636600461277e565b610c3e565b6102c7610ca1565b6000546001600160a01b03165b6040516001600160a01b0390911681526020016102ab565b6102c7610486366004612691565b610d08565b6103566104993660046127b8565b610dd5565b6103566104ac3660046127b8565b610ea1565b6104f36104bf366004612691565b60076020526000908152604090208054600182015460028301546003909301546001600160a01b0392831693919092169184565b604080516001600160a01b0395861681529490931660208501529183015260608201526080016102ab565b61035660095481565b61035661053536600461277e565b60056020526000908152604090205481565b6102c76105553660046126f6565b610f34565b6104607f000000000000000000000000000000000000000000000000000000000000000081565b6102c76110cb565b61029f61059736600461277e565b60026020526000908152604090205460ff1681565b61029f6105ba36600461277e565b6001600160a01b031660009081526002602052604090205460ff1690565b6102c76105e636600461277e565b6110d4565b6102c76105f936600461277e565b611137565b61035661060c36600461277e565b60066020526000908152604090205481565b61035661062c366004612816565b611216565b6102c761063f3660046126f6565b61162b565b3360009081526002602052604090205460ff166106a15760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b60448201526064015b60405180910390fd5b8281146106e25760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610698565b60005b838110156107e0578282828181106106ff576106ff612905565b905060200201356008600087878581811061071c5761071c612905565b9050602002016020810190610731919061277e565b6001600160a01b031681526020810191909152604001600020557fceaad6533bfb481492fb3e08ef19297f46611b8fa9de5ef4cf8dc23a56ad09ce85858381811061077e5761077e612905565b9050602002016020810190610793919061277e565b8484848181106107a5576107a5612905565b604080516001600160a01b0390951685526020918202939093013590840152500160405180910390a1806107d881612931565b9150506106e5565b5050505050565b6000546001600160a01b031633146108415760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b61084a816117c2565b50565b3360009081526002602052604090205460ff166108a55760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b6044820152606401610698565b60098190556040518181527fc0a39f234199b125fb93713c4d067bdcebbf691087f87b79c0feb92b156ba8b6906020015b60405180910390a150565b3360009081526001602052604090205460ff166109405760405162461bcd60e51b815260206004820152601460248201527f43616c6c6572206973206e6f74207061757365720000000000000000000000006044820152606401610698565b61094861187f565b565b3360009081526002602052604090205460ff166109a25760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b6044820152606401610698565b8281146109e35760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610698565b60005b838110156107e057828282818110610a0057610a00612905565b9050602002013560056000878785818110610a1d57610a1d612905565b9050602002016020810190610a32919061277e565b6001600160a01b031681526020810191909152604001600020557f608e49c22994f20b5d3496dca088b88dfd81b4a3e8cc3809ea1e10a320107e89858583818110610a7f57610a7f612905565b9050602002016020810190610a94919061277e565b848484818110610aa657610aa6612905565b604080516001600160a01b0390951685526020918202939093013590840152500160405180910390a180610ad981612931565b9150506109e6565b3360009081526002602052604090205460ff16610b395760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b6044820152606401610698565b60038190556040518181527f2664fec2ff76486ac58ed087310855b648b15b9d19f3de8529e95f7c46b7d6b3906020016108d6565b6000546001600160a01b03163314610bc85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b61084a81611925565b61094833611925565b6000546001600160a01b03163314610c345760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b61094860006119de565b6000546001600160a01b03163314610c985760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b61084a81611a3b565b3360009081526001602052604090205460ff16610d005760405162461bcd60e51b815260206004820152601460248201527f43616c6c6572206973206e6f74207061757365720000000000000000000000006044820152606401610698565b610948611af9565b600054600160a01b900460ff1615610d555760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610698565b6000610d6082611b81565b6020810151815160408084015190516340c10f1960e01b81526001600160a01b039283166004820152602481019190915292935016906340c10f1990604401600060405180830381600087803b158015610db957600080fd5b505af1158015610dcd573d6000803e3d6000fd5b505050505050565b60008054600160a01b900460ff1615610e235760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610698565b6000610e328787878787611d53565b60405163079cc67960e41b8152336004820152602481018890529091506001600160a01b038816906379cc6790906044015b600060405180830381600087803b158015610e7e57600080fd5b505af1158015610e92573d6000803e3d6000fd5b50929998505050505050505050565b60008054600160a01b900460ff1615610eef5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610698565b6000610efe8787878787611d53565b604051632770a7eb60e21b8152336004820152602481018890529091506001600160a01b03881690639dc29fac90604401610e64565b3360009081526002602052604090205460ff16610f8c5760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b6044820152606401610698565b828114610fcd5760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610698565b60005b838110156107e057828282818110610fea57610fea612905565b90506020020135600b600087878581811061100757611007612905565b905060200201602081019061101c919061277e565b6001600160a01b031681526020810191909152604001600020557f3796cd0b17a8734f8da819920625598e9a18be490f686725282e5383f1d0668385858381811061106957611069612905565b905060200201602081019061107e919061277e565b84848481811061109057611090612905565b604080516001600160a01b0390951685526020918202939093013590840152500160405180910390a1806110c381612931565b915050610fd0565b61094833611fc6565b6000546001600160a01b0316331461112e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b61084a81611fc6565b6000546001600160a01b031633146111915760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b6001600160a01b03811661120d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610698565b61084a816119de565b60008054600160a01b900460ff16156112645760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610698565b600046306040516020016112a192919091825260601b6bffffffffffffffffffffffff1916602082015263135a5b9d60e21b603482015260380190565b6040516020818303038152906040528051906020012090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663682dbc22828c8c6040516020016112fd9392919061294c565b6040516020818303038152906040528a8a8a8a8a8a6040518863ffffffff1660e01b81526004016113349796959493929190612ab3565b60006040518083038186803b15801561134c57600080fd5b505afa158015611360573d6000803e3d6000fd5b5050505060006113a58b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061207f92505050565b6020818101518251604080850151606080870151608088015160a089015185516bffffffffffffffffffffffff1998851b8916818b015296841b88166034880152604887019490945290821b8616606886015277ffffffffffffffffffffffffffffffffffffffffffffffff1960c09190911b16607c850152608484019190915230901b90921660a48201528151808203609801815260b890910182528051908301206000818152600a9093529120549192509060ff16156114995760405162461bcd60e51b815260206004820152600d60248201526c7265636f72642065786973747360981b6044820152606401610698565b6000818152600a602052604090819020805460ff191660011790558251908301516114c491906121e1565b81516001600160a01b031660009081526008602052604090205480158015906114f05750808360400151115b156115125761150d828460200151856000015186604001516122f9565b611582565b8251602084015160408086015190516340c10f1960e01b81526001600160a01b03928316600482015260248101919091529116906340c10f1990604401600060405180830381600087803b15801561156957600080fd5b505af115801561157d573d6000803e3d6000fd5b505050505b7f5bc84ecccfced5bb04bfc7f3efcdbe7f5cd21949ef146811b4d1967fe41f777a8284600001518560200151866040015187608001518860a00151896060015160405161161397969594939291909687526001600160a01b0395861660208801529385166040870152606086019290925267ffffffffffffffff16608085015260a08401521660c082015260e00190565b60405180910390a1509b9a5050505050505050505050565b3360009081526002602052604090205460ff166116835760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b6044820152606401610698565b8281146116c45760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610698565b60005b838110156107e0578282828181106116e1576116e1612905565b90506020020135600c60008787858181106116fe576116fe612905565b9050602002016020810190611713919061277e565b6001600160a01b031681526020810191909152604001600020557fa3181379f6db47d9037efc6b6e8e3efe8c55ddb090b4f0512c152f97c4e47da585858381811061176057611760612905565b9050602002016020810190611775919061277e565b84848481811061178757611787612905565b604080516001600160a01b0390951685526020918202939093013590840152500160405180910390a1806117ba81612931565b9150506116c7565b6001600160a01b03811660009081526002602052604090205460ff161561182b5760405162461bcd60e51b815260206004820152601b60248201527f4163636f756e7420697320616c726561647920676f7665726e6f7200000000006044820152606401610698565b6001600160a01b038116600081815260026020908152604091829020805460ff1916600117905590519182527fdc5a48d79e2e147530ff63ecdbed5a5a66adb9d5cf339384d5d076da197c40b591016108d6565b600054600160a01b900460ff166118d85760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610698565b6000805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b03811660009081526001602052604090205460ff1661198d5760405162461bcd60e51b815260206004820152601560248201527f4163636f756e74206973206e6f742070617573657200000000000000000000006044820152606401610698565b6001600160a01b038116600081815260016020908152604091829020805460ff1916905590519182527fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e91016108d6565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811660009081526001602052604090205460ff1615611aa45760405162461bcd60e51b815260206004820152601960248201527f4163636f756e7420697320616c726561647920706175736572000000000000006044820152606401610698565b6001600160a01b038116600081815260016020818152604092839020805460ff191690921790915590519182527f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f891016108d6565b600054600160a01b900460ff1615611b465760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610698565b6000805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586119083390565b604080516080810182526000808252602082018190529181018290526060810191909152600082815260076020908152604091829020825160808101845281546001600160a01b0390811682526001830154169281019290925260028101549282019290925260039091015460608201819052611c405760405162461bcd60e51b815260206004820152601a60248201527f64656c61796564207472616e73666572206e6f742065786973740000000000006044820152606401610698565b6009548160600151611c529190612b4f565b4211611ca05760405162461bcd60e51b815260206004820152601d60248201527f64656c61796564207472616e73666572207374696c6c206c6f636b65640000006044820152606401610698565b6000838152600760209081526040808320805473ffffffffffffffffffffffffffffffffffffffff199081168255600182018054909116905560028101849055600301929092558251908301518383015192517f3b40e5089937425d14cdd96947e5661868357e224af59bd8b24a4b8a330d442693611d4593889390929091909384526001600160a01b03928316602085015291166040830152606082015260800190565b60405180910390a192915050565b6001600160a01b0385166000908152600b60205260408120548511611dba5760405162461bcd60e51b815260206004820152601060248201527f616d6f756e7420746f6f20736d616c6c000000000000000000000000000000006044820152606401610698565b6001600160a01b0386166000908152600c60205260409020541580611df757506001600160a01b0386166000908152600c60205260409020548511155b611e435760405162461bcd60e51b815260206004820152601060248201527f616d6f756e7420746f6f206c61726765000000000000000000000000000000006044820152606401610698565b6040516bffffffffffffffffffffffff1933606090811b8216602084015288811b821660348401526048830188905277ffffffffffffffffffffffffffffffffffffffffffffffff1960c088811b8216606886015287831b8416607086015286811b8216608486015246901b16608c84015230901b16609482015260009060a80160408051601f1981840301815291815281516020928301206000818152600a90935291205490915060ff1615611f2c5760405162461bcd60e51b815260206004820152600d60248201526c7265636f72642065786973747360981b6044820152606401610698565b6000818152600a6020908152604091829020805460ff1916600117905581518381526001600160a01b038a81169282019290925233928101929092526060820188905267ffffffffffffffff878116608084015290861660a0830152841660c08201527f6298d7b58f235730b3b399dc5c282f15dae8b022e5fbbf89cee21fd83c8810a39060e00160405180910390a19695505050505050565b6001600160a01b03811660009081526002602052604090205460ff1661202e5760405162461bcd60e51b815260206004820152601760248201527f4163636f756e74206973206e6f7420676f7665726e6f720000000000000000006044820152606401610698565b6001600160a01b038116600081815260026020908152604091829020805460ff1916905590519182527f1ebe834e73d60a5fec822c1e1727d34bc79f2ad977ed504581cc1822fe20fb5b91016108d6565b6040805160c08101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905283518085019094528184528301849052909190805b602083015151835110156121d9576120dd83612419565b9092509050816001141561210c576120fc6120f784612453565b612510565b6001600160a01b031684526120c6565b8160021415612134576121216120f784612453565b6001600160a01b031660208501526120c6565b81600314156121585761214e61214984612453565b612521565b60408501526120c6565b81600414156121805761216d6120f784612453565b6001600160a01b031660608501526120c6565b81600514156121a65761219283612558565b67ffffffffffffffff1660808501526120c6565b81600614156121ca576121c06121bb84612453565b6125da565b60a08501526120c6565b6121d483826125f2565b6120c6565b505050919050565b6003546121ec575050565b6001600160a01b0382166000908152600560205260409020548061220f57505050565b6001600160a01b038316600090815260046020526040812054600354909142916122398184612b67565b6122439190612b89565b6001600160a01b03871660009081526006602052604090205490915081111561226e5784925061227b565b6122788584612b4f565b92505b838311156122cb5760405162461bcd60e51b815260206004820152601260248201527f766f6c756d6520657863656564732063617000000000000000000000000000006044820152606401610698565b506001600160a01b039094166000908152600460209081526040808320939093556006905220929092555050565b600084815260076020526040902060030154156123585760405162461bcd60e51b815260206004820152601f60248201527f64656c61796564207472616e7366657220616c726561647920657869737473006044820152606401610698565b604080516080810182526001600160a01b0380861682528481166020808401918252838501868152426060860190815260008b81526007909352918690209451855490851673ffffffffffffffffffffffffffffffffffffffff1991821617865592516001860180549190951693169290921790925551600283015551600390910155517fcbcfffe5102114216a85d3aceb14ad4b81a3935b1b5c468fadf3889eb9c5dce69061240b9086815260200190565b60405180910390a150505050565b600080600061242784612558565b9050612434600882612b67565b925080600716600581111561244b5761244b612ba8565b915050915091565b6060600061246083612558565b905060008184600001516124749190612b4f565b905083602001515181111561248857600080fd5b8167ffffffffffffffff8111156124a1576124a1612bbe565b6040519080825280601f01601f1916602001820160405280156124cb576020820181803683370190505b50602080860151865192955091818601919083010160005b858110156125055781810151838201526124fe602082612b4f565b90506124e3565b505050935250919050565b600061251b82612669565b92915050565b600060208251111561253257600080fd5b60208201519050815160206125479190612bd4565b612552906008612b89565b1c919050565b602080820151825181019091015160009182805b600a8110156125d45783811a9150612585816007612b89565b82607f16901b8517945081608016600014156125c2576125a6816001612b4f565b865187906125b5908390612b4f565b9052509395945050505050565b806125cc81612931565b91505061256c565b50600080fd5b600081516020146125ea57600080fd5b506020015190565b600081600581111561260657612606612ba8565b141561261a5761261582612558565b505050565b600281600581111561262e5761262e612ba8565b141561027757600061263f83612558565b905080836000018181516126539190612b4f565b9052506020830151518351111561261557600080fd5b6000815160141461267957600080fd5b50602001516c01000000000000000000000000900490565b6000602082840312156126a357600080fd5b5035919050565b60008083601f8401126126bc57600080fd5b50813567ffffffffffffffff8111156126d457600080fd5b6020830191508360208260051b85010111156126ef57600080fd5b9250929050565b6000806000806040858703121561270c57600080fd5b843567ffffffffffffffff8082111561272457600080fd5b612730888389016126aa565b9096509450602087013591508082111561274957600080fd5b50612756878288016126aa565b95989497509550505050565b80356001600160a01b038116811461277957600080fd5b919050565b60006020828403121561279057600080fd5b61279982612762565b9392505050565b803567ffffffffffffffff8116811461277957600080fd5b600080600080600060a086880312156127d057600080fd5b6127d986612762565b9450602086013593506127ee604087016127a0565b92506127fc60608701612762565b915061280a608087016127a0565b90509295509295909350565b6000806000806000806000806080898b03121561283257600080fd5b883567ffffffffffffffff8082111561284a57600080fd5b818b0191508b601f83011261285e57600080fd5b81358181111561286d57600080fd5b8c602082850101111561287f57600080fd5b60209283019a509850908a0135908082111561289a57600080fd5b6128a68c838d016126aa565b909850965060408b01359150808211156128bf57600080fd5b6128cb8c838d016126aa565b909650945060608b01359150808211156128e457600080fd5b506128f18b828c016126aa565b999c989b5096995094979396929594505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156129455761294561291b565b5060010190565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b818352600060208085019450848460051b86018460005b87811015612a105783830389528135601e198836030181126129c757600080fd5b8701803567ffffffffffffffff8111156129e057600080fd5b8036038913156129ef57600080fd5b6129fc8582898501612966565b9a87019a94505050908401906001016129a6565b5090979650505050505050565b8183526000602080850194508260005b85811015612a59576001600160a01b03612a4683612762565b1687529582019590820190600101612a2d565b509495945050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115612a9657600080fd5b8260051b8083602087013760009401602001938452509192915050565b608081526000885180608084015260005b81811015612ae1576020818c0181015160a0868401015201612ac4565b81811115612af357600060a083860101525b50601f01601f1916820182810360a09081016020850152612b17908201898b61298f565b90508281036040840152612b2c818789612a1d565b90508281036060840152612b41818587612a64565b9a9950505050505050505050565b60008219821115612b6257612b6261291b565b500190565b600082612b8457634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615612ba357612ba361291b565b500290565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b600082821015612be657612be661291b565b50039056fea2646970667358221220cf1de8e39feed918e8a2548fc8f45c9963a65d37beb2c51decc88e847298a7d164736f6c63430008090033000000000000000000000000841ce48f9446c8e281d3f1444cb859b4a6d0738c

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106102775760003560e01c806382dc1ec411610160578063bf4816f0116100d8578063eecdac881161008c578063f832138311610071578063f8321383146105fe578063f87343021461061e578063f9a8ea081461063157600080fd5b8063eecdac88146105d8578063f2fde38b146105eb57600080fd5b8063e026049c116100bd578063e026049c14610581578063e3eece2614610589578063e43581b8146105ac57600080fd5b8063bf4816f014610547578063ccf2683b1461055a57600080fd5b80639e422c331161012f578063adc0d57f11610114578063adc0d57f146104b1578063b1c94d941461051e578063b5f2bc471461052757600080fd5b80639e422c331461048b578063a00293011461049e57600080fd5b806382dc1ec4146104385780638456cb591461044b5780638da5cb5b146104535780639e25fc5c1461047857600080fd5b806354eea796116101f35780636b2c0f55116101c2578063715018a6116101a7578063715018a6146103ed5780637f856013146103f557806380f51c121461041557600080fd5b80636b2c0f55146103d25780636ef8d66d146103e557600080fd5b806354eea7961461038457806357d775f8146103975780635c975abb146103a057806360216b00146103b257600080fd5b80633f4ba83a1161024a57806347b16c6c1161022f57806347b16c6c14610323578063497bf3b21461033657806352532faa1461036457600080fd5b80633f4ba83a146102ef57806346fbf68e146102f757600080fd5b806301e647251461027c57806317bdbae5146102b45780633c4a25d0146102c95780633d572107146102dc575b600080fd5b61029f61028a366004612691565b600a6020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6102c76102c23660046126f6565b610644565b005b6102c76102d736600461277e565b6107e7565b6102c76102ea366004612691565b61084d565b6102c76108e1565b61029f61030536600461277e565b6001600160a01b031660009081526001602052604090205460ff1690565b6102c76103313660046126f6565b61094a565b61035661034436600461277e565b600c6020526000908152604090205481565b6040519081526020016102ab565b61035661037236600461277e565b60086020526000908152604090205481565b6102c7610392366004612691565b610ae1565b61035660035481565b600054600160a01b900460ff1661029f565b6103566103c036600461277e565b60046020526000908152604090205481565b6102c76103e036600461277e565b610b6e565b6102c7610bd1565b6102c7610bda565b61035661040336600461277e565b600b6020526000908152604090205481565b61029f61042336600461277e565b60016020526000908152604090205460ff1681565b6102c761044636600461277e565b610c3e565b6102c7610ca1565b6000546001600160a01b03165b6040516001600160a01b0390911681526020016102ab565b6102c7610486366004612691565b610d08565b6103566104993660046127b8565b610dd5565b6103566104ac3660046127b8565b610ea1565b6104f36104bf366004612691565b60076020526000908152604090208054600182015460028301546003909301546001600160a01b0392831693919092169184565b604080516001600160a01b0395861681529490931660208501529183015260608201526080016102ab565b61035660095481565b61035661053536600461277e565b60056020526000908152604090205481565b6102c76105553660046126f6565b610f34565b6104607f000000000000000000000000841ce48f9446c8e281d3f1444cb859b4a6d0738c81565b6102c76110cb565b61029f61059736600461277e565b60026020526000908152604090205460ff1681565b61029f6105ba36600461277e565b6001600160a01b031660009081526002602052604090205460ff1690565b6102c76105e636600461277e565b6110d4565b6102c76105f936600461277e565b611137565b61035661060c36600461277e565b60066020526000908152604090205481565b61035661062c366004612816565b611216565b6102c761063f3660046126f6565b61162b565b3360009081526002602052604090205460ff166106a15760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b60448201526064015b60405180910390fd5b8281146106e25760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610698565b60005b838110156107e0578282828181106106ff576106ff612905565b905060200201356008600087878581811061071c5761071c612905565b9050602002016020810190610731919061277e565b6001600160a01b031681526020810191909152604001600020557fceaad6533bfb481492fb3e08ef19297f46611b8fa9de5ef4cf8dc23a56ad09ce85858381811061077e5761077e612905565b9050602002016020810190610793919061277e565b8484848181106107a5576107a5612905565b604080516001600160a01b0390951685526020918202939093013590840152500160405180910390a1806107d881612931565b9150506106e5565b5050505050565b6000546001600160a01b031633146108415760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b61084a816117c2565b50565b3360009081526002602052604090205460ff166108a55760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b6044820152606401610698565b60098190556040518181527fc0a39f234199b125fb93713c4d067bdcebbf691087f87b79c0feb92b156ba8b6906020015b60405180910390a150565b3360009081526001602052604090205460ff166109405760405162461bcd60e51b815260206004820152601460248201527f43616c6c6572206973206e6f74207061757365720000000000000000000000006044820152606401610698565b61094861187f565b565b3360009081526002602052604090205460ff166109a25760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b6044820152606401610698565b8281146109e35760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610698565b60005b838110156107e057828282818110610a0057610a00612905565b9050602002013560056000878785818110610a1d57610a1d612905565b9050602002016020810190610a32919061277e565b6001600160a01b031681526020810191909152604001600020557f608e49c22994f20b5d3496dca088b88dfd81b4a3e8cc3809ea1e10a320107e89858583818110610a7f57610a7f612905565b9050602002016020810190610a94919061277e565b848484818110610aa657610aa6612905565b604080516001600160a01b0390951685526020918202939093013590840152500160405180910390a180610ad981612931565b9150506109e6565b3360009081526002602052604090205460ff16610b395760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b6044820152606401610698565b60038190556040518181527f2664fec2ff76486ac58ed087310855b648b15b9d19f3de8529e95f7c46b7d6b3906020016108d6565b6000546001600160a01b03163314610bc85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b61084a81611925565b61094833611925565b6000546001600160a01b03163314610c345760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b61094860006119de565b6000546001600160a01b03163314610c985760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b61084a81611a3b565b3360009081526001602052604090205460ff16610d005760405162461bcd60e51b815260206004820152601460248201527f43616c6c6572206973206e6f74207061757365720000000000000000000000006044820152606401610698565b610948611af9565b600054600160a01b900460ff1615610d555760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610698565b6000610d6082611b81565b6020810151815160408084015190516340c10f1960e01b81526001600160a01b039283166004820152602481019190915292935016906340c10f1990604401600060405180830381600087803b158015610db957600080fd5b505af1158015610dcd573d6000803e3d6000fd5b505050505050565b60008054600160a01b900460ff1615610e235760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610698565b6000610e328787878787611d53565b60405163079cc67960e41b8152336004820152602481018890529091506001600160a01b038816906379cc6790906044015b600060405180830381600087803b158015610e7e57600080fd5b505af1158015610e92573d6000803e3d6000fd5b50929998505050505050505050565b60008054600160a01b900460ff1615610eef5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610698565b6000610efe8787878787611d53565b604051632770a7eb60e21b8152336004820152602481018890529091506001600160a01b03881690639dc29fac90604401610e64565b3360009081526002602052604090205460ff16610f8c5760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b6044820152606401610698565b828114610fcd5760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610698565b60005b838110156107e057828282818110610fea57610fea612905565b90506020020135600b600087878581811061100757611007612905565b905060200201602081019061101c919061277e565b6001600160a01b031681526020810191909152604001600020557f3796cd0b17a8734f8da819920625598e9a18be490f686725282e5383f1d0668385858381811061106957611069612905565b905060200201602081019061107e919061277e565b84848481811061109057611090612905565b604080516001600160a01b0390951685526020918202939093013590840152500160405180910390a1806110c381612931565b915050610fd0565b61094833611fc6565b6000546001600160a01b0316331461112e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b61084a81611fc6565b6000546001600160a01b031633146111915760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610698565b6001600160a01b03811661120d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610698565b61084a816119de565b60008054600160a01b900460ff16156112645760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610698565b600046306040516020016112a192919091825260601b6bffffffffffffffffffffffff1916602082015263135a5b9d60e21b603482015260380190565b6040516020818303038152906040528051906020012090507f000000000000000000000000841ce48f9446c8e281d3f1444cb859b4a6d0738c6001600160a01b031663682dbc22828c8c6040516020016112fd9392919061294c565b6040516020818303038152906040528a8a8a8a8a8a6040518863ffffffff1660e01b81526004016113349796959493929190612ab3565b60006040518083038186803b15801561134c57600080fd5b505afa158015611360573d6000803e3d6000fd5b5050505060006113a58b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061207f92505050565b6020818101518251604080850151606080870151608088015160a089015185516bffffffffffffffffffffffff1998851b8916818b015296841b88166034880152604887019490945290821b8616606886015277ffffffffffffffffffffffffffffffffffffffffffffffff1960c09190911b16607c850152608484019190915230901b90921660a48201528151808203609801815260b890910182528051908301206000818152600a9093529120549192509060ff16156114995760405162461bcd60e51b815260206004820152600d60248201526c7265636f72642065786973747360981b6044820152606401610698565b6000818152600a602052604090819020805460ff191660011790558251908301516114c491906121e1565b81516001600160a01b031660009081526008602052604090205480158015906114f05750808360400151115b156115125761150d828460200151856000015186604001516122f9565b611582565b8251602084015160408086015190516340c10f1960e01b81526001600160a01b03928316600482015260248101919091529116906340c10f1990604401600060405180830381600087803b15801561156957600080fd5b505af115801561157d573d6000803e3d6000fd5b505050505b7f5bc84ecccfced5bb04bfc7f3efcdbe7f5cd21949ef146811b4d1967fe41f777a8284600001518560200151866040015187608001518860a00151896060015160405161161397969594939291909687526001600160a01b0395861660208801529385166040870152606086019290925267ffffffffffffffff16608085015260a08401521660c082015260e00190565b60405180910390a1509b9a5050505050505050505050565b3360009081526002602052604090205460ff166116835760405162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1033b7bb32b93737b960511b6044820152606401610698565b8281146116c45760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610698565b60005b838110156107e0578282828181106116e1576116e1612905565b90506020020135600c60008787858181106116fe576116fe612905565b9050602002016020810190611713919061277e565b6001600160a01b031681526020810191909152604001600020557fa3181379f6db47d9037efc6b6e8e3efe8c55ddb090b4f0512c152f97c4e47da585858381811061176057611760612905565b9050602002016020810190611775919061277e565b84848481811061178757611787612905565b604080516001600160a01b0390951685526020918202939093013590840152500160405180910390a1806117ba81612931565b9150506116c7565b6001600160a01b03811660009081526002602052604090205460ff161561182b5760405162461bcd60e51b815260206004820152601b60248201527f4163636f756e7420697320616c726561647920676f7665726e6f7200000000006044820152606401610698565b6001600160a01b038116600081815260026020908152604091829020805460ff1916600117905590519182527fdc5a48d79e2e147530ff63ecdbed5a5a66adb9d5cf339384d5d076da197c40b591016108d6565b600054600160a01b900460ff166118d85760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610698565b6000805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b03811660009081526001602052604090205460ff1661198d5760405162461bcd60e51b815260206004820152601560248201527f4163636f756e74206973206e6f742070617573657200000000000000000000006044820152606401610698565b6001600160a01b038116600081815260016020908152604091829020805460ff1916905590519182527fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e91016108d6565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811660009081526001602052604090205460ff1615611aa45760405162461bcd60e51b815260206004820152601960248201527f4163636f756e7420697320616c726561647920706175736572000000000000006044820152606401610698565b6001600160a01b038116600081815260016020818152604092839020805460ff191690921790915590519182527f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f891016108d6565b600054600160a01b900460ff1615611b465760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610698565b6000805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586119083390565b604080516080810182526000808252602082018190529181018290526060810191909152600082815260076020908152604091829020825160808101845281546001600160a01b0390811682526001830154169281019290925260028101549282019290925260039091015460608201819052611c405760405162461bcd60e51b815260206004820152601a60248201527f64656c61796564207472616e73666572206e6f742065786973740000000000006044820152606401610698565b6009548160600151611c529190612b4f565b4211611ca05760405162461bcd60e51b815260206004820152601d60248201527f64656c61796564207472616e73666572207374696c6c206c6f636b65640000006044820152606401610698565b6000838152600760209081526040808320805473ffffffffffffffffffffffffffffffffffffffff199081168255600182018054909116905560028101849055600301929092558251908301518383015192517f3b40e5089937425d14cdd96947e5661868357e224af59bd8b24a4b8a330d442693611d4593889390929091909384526001600160a01b03928316602085015291166040830152606082015260800190565b60405180910390a192915050565b6001600160a01b0385166000908152600b60205260408120548511611dba5760405162461bcd60e51b815260206004820152601060248201527f616d6f756e7420746f6f20736d616c6c000000000000000000000000000000006044820152606401610698565b6001600160a01b0386166000908152600c60205260409020541580611df757506001600160a01b0386166000908152600c60205260409020548511155b611e435760405162461bcd60e51b815260206004820152601060248201527f616d6f756e7420746f6f206c61726765000000000000000000000000000000006044820152606401610698565b6040516bffffffffffffffffffffffff1933606090811b8216602084015288811b821660348401526048830188905277ffffffffffffffffffffffffffffffffffffffffffffffff1960c088811b8216606886015287831b8416607086015286811b8216608486015246901b16608c84015230901b16609482015260009060a80160408051601f1981840301815291815281516020928301206000818152600a90935291205490915060ff1615611f2c5760405162461bcd60e51b815260206004820152600d60248201526c7265636f72642065786973747360981b6044820152606401610698565b6000818152600a6020908152604091829020805460ff1916600117905581518381526001600160a01b038a81169282019290925233928101929092526060820188905267ffffffffffffffff878116608084015290861660a0830152841660c08201527f6298d7b58f235730b3b399dc5c282f15dae8b022e5fbbf89cee21fd83c8810a39060e00160405180910390a19695505050505050565b6001600160a01b03811660009081526002602052604090205460ff1661202e5760405162461bcd60e51b815260206004820152601760248201527f4163636f756e74206973206e6f7420676f7665726e6f720000000000000000006044820152606401610698565b6001600160a01b038116600081815260026020908152604091829020805460ff1916905590519182527f1ebe834e73d60a5fec822c1e1727d34bc79f2ad977ed504581cc1822fe20fb5b91016108d6565b6040805160c08101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905283518085019094528184528301849052909190805b602083015151835110156121d9576120dd83612419565b9092509050816001141561210c576120fc6120f784612453565b612510565b6001600160a01b031684526120c6565b8160021415612134576121216120f784612453565b6001600160a01b031660208501526120c6565b81600314156121585761214e61214984612453565b612521565b60408501526120c6565b81600414156121805761216d6120f784612453565b6001600160a01b031660608501526120c6565b81600514156121a65761219283612558565b67ffffffffffffffff1660808501526120c6565b81600614156121ca576121c06121bb84612453565b6125da565b60a08501526120c6565b6121d483826125f2565b6120c6565b505050919050565b6003546121ec575050565b6001600160a01b0382166000908152600560205260409020548061220f57505050565b6001600160a01b038316600090815260046020526040812054600354909142916122398184612b67565b6122439190612b89565b6001600160a01b03871660009081526006602052604090205490915081111561226e5784925061227b565b6122788584612b4f565b92505b838311156122cb5760405162461bcd60e51b815260206004820152601260248201527f766f6c756d6520657863656564732063617000000000000000000000000000006044820152606401610698565b506001600160a01b039094166000908152600460209081526040808320939093556006905220929092555050565b600084815260076020526040902060030154156123585760405162461bcd60e51b815260206004820152601f60248201527f64656c61796564207472616e7366657220616c726561647920657869737473006044820152606401610698565b604080516080810182526001600160a01b0380861682528481166020808401918252838501868152426060860190815260008b81526007909352918690209451855490851673ffffffffffffffffffffffffffffffffffffffff1991821617865592516001860180549190951693169290921790925551600283015551600390910155517fcbcfffe5102114216a85d3aceb14ad4b81a3935b1b5c468fadf3889eb9c5dce69061240b9086815260200190565b60405180910390a150505050565b600080600061242784612558565b9050612434600882612b67565b925080600716600581111561244b5761244b612ba8565b915050915091565b6060600061246083612558565b905060008184600001516124749190612b4f565b905083602001515181111561248857600080fd5b8167ffffffffffffffff8111156124a1576124a1612bbe565b6040519080825280601f01601f1916602001820160405280156124cb576020820181803683370190505b50602080860151865192955091818601919083010160005b858110156125055781810151838201526124fe602082612b4f565b90506124e3565b505050935250919050565b600061251b82612669565b92915050565b600060208251111561253257600080fd5b60208201519050815160206125479190612bd4565b612552906008612b89565b1c919050565b602080820151825181019091015160009182805b600a8110156125d45783811a9150612585816007612b89565b82607f16901b8517945081608016600014156125c2576125a6816001612b4f565b865187906125b5908390612b4f565b9052509395945050505050565b806125cc81612931565b91505061256c565b50600080fd5b600081516020146125ea57600080fd5b506020015190565b600081600581111561260657612606612ba8565b141561261a5761261582612558565b505050565b600281600581111561262e5761262e612ba8565b141561027757600061263f83612558565b905080836000018181516126539190612b4f565b9052506020830151518351111561261557600080fd5b6000815160141461267957600080fd5b50602001516c01000000000000000000000000900490565b6000602082840312156126a357600080fd5b5035919050565b60008083601f8401126126bc57600080fd5b50813567ffffffffffffffff8111156126d457600080fd5b6020830191508360208260051b85010111156126ef57600080fd5b9250929050565b6000806000806040858703121561270c57600080fd5b843567ffffffffffffffff8082111561272457600080fd5b612730888389016126aa565b9096509450602087013591508082111561274957600080fd5b50612756878288016126aa565b95989497509550505050565b80356001600160a01b038116811461277957600080fd5b919050565b60006020828403121561279057600080fd5b61279982612762565b9392505050565b803567ffffffffffffffff8116811461277957600080fd5b600080600080600060a086880312156127d057600080fd5b6127d986612762565b9450602086013593506127ee604087016127a0565b92506127fc60608701612762565b915061280a608087016127a0565b90509295509295909350565b6000806000806000806000806080898b03121561283257600080fd5b883567ffffffffffffffff8082111561284a57600080fd5b818b0191508b601f83011261285e57600080fd5b81358181111561286d57600080fd5b8c602082850101111561287f57600080fd5b60209283019a509850908a0135908082111561289a57600080fd5b6128a68c838d016126aa565b909850965060408b01359150808211156128bf57600080fd5b6128cb8c838d016126aa565b909650945060608b01359150808211156128e457600080fd5b506128f18b828c016126aa565b999c989b5096995094979396929594505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156129455761294561291b565b5060010190565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b818352600060208085019450848460051b86018460005b87811015612a105783830389528135601e198836030181126129c757600080fd5b8701803567ffffffffffffffff8111156129e057600080fd5b8036038913156129ef57600080fd5b6129fc8582898501612966565b9a87019a94505050908401906001016129a6565b5090979650505050505050565b8183526000602080850194508260005b85811015612a59576001600160a01b03612a4683612762565b1687529582019590820190600101612a2d565b509495945050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115612a9657600080fd5b8260051b8083602087013760009401602001938452509192915050565b608081526000885180608084015260005b81811015612ae1576020818c0181015160a0868401015201612ac4565b81811115612af357600060a083860101525b50601f01601f1916820182810360a09081016020850152612b17908201898b61298f565b90508281036040840152612b2c818789612a1d565b90508281036060840152612b41818587612a64565b9a9950505050505050505050565b60008219821115612b6257612b6261291b565b500190565b600082612b8457634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615612ba357612ba361291b565b500290565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b600082821015612be657612be661291b565b50039056fea2646970667358221220cf1de8e39feed918e8a2548fc8f45c9963a65d37beb2c51decc88e847298a7d164736f6c63430008090033