ETH Price: $3,447.36 (+0.76%)
Gas: 11 Gwei

Contract

0x46A71e786c34714928390782e9e50eE1C2fa9989
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x612c0661131133242021-08-28 10:29:011054 days ago1630146541IN
 Create: ExchangeWithdrawals
0 ETH0.1211141349

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ExchangeWithdrawals

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 999999 runs

Other Settings:
default evmVersion, Apache-2.0 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2021-08-28
*/

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
// File: contracts/lib/AddressUtil.sol

// Copyright 2017 Loopring Technology Limited.


/// @title Utility Functions for addresses
/// @author Daniel Wang - <[email protected]>
/// @author Brecht Devos - <[email protected]>
library AddressUtil
{
    using AddressUtil for *;

    function isContract(
        address addr
        )
        internal
        view
        returns (bool)
    {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(addr) }
        return (codehash != 0x0 &&
                codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470);
    }

    function toPayable(
        address addr
        )
        internal
        pure
        returns (address payable)
    {
        return payable(addr);
    }

    // Works like address.send but with a customizable gas limit
    // Make sure your code is safe for reentrancy when using this function!
    function sendETH(
        address to,
        uint    amount,
        uint    gasLimit
        )
        internal
        returns (bool success)
    {
        if (amount == 0) {
            return true;
        }
        address payable recipient = to.toPayable();
        /* solium-disable-next-line */
        (success, ) = recipient.call{value: amount, gas: gasLimit}("");
    }

    // Works like address.transfer but with a customizable gas limit
    // Make sure your code is safe for reentrancy when using this function!
    function sendETHAndVerify(
        address to,
        uint    amount,
        uint    gasLimit
        )
        internal
        returns (bool success)
    {
        success = to.sendETH(amount, gasLimit);
        require(success, "TRANSFER_FAILURE");
    }

    // Works like call but is slightly more efficient when data
    // needs to be copied from memory to do the call.
    function fastCall(
        address to,
        uint    gasLimit,
        uint    value,
        bytes   memory data
        )
        internal
        returns (bool success, bytes memory returnData)
    {
        if (to != address(0)) {
            assembly {
                // Do the call
                success := call(gasLimit, to, value, add(data, 32), mload(data), 0, 0)
                // Copy the return data
                let size := returndatasize()
                returnData := mload(0x40)
                mstore(returnData, size)
                returndatacopy(add(returnData, 32), 0, size)
                // Update free memory pointer
                mstore(0x40, add(returnData, add(32, size)))
            }
        }
    }

    // Like fastCall, but throws when the call is unsuccessful.
    function fastCallAndVerify(
        address to,
        uint    gasLimit,
        uint    value,
        bytes   memory data
        )
        internal
        returns (bytes memory returnData)
    {
        bool success;
        (success, returnData) = fastCall(to, gasLimit, value, data);
        if (!success) {
            assembly {
                revert(add(returnData, 32), mload(returnData))
            }
        }
    }
}

// File: contracts/thirdparty/BytesUtil.sol

//Mainly taken from https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol

library BytesUtil {

    function concat(
        bytes memory _preBytes,
        bytes memory _postBytes
    )
        internal
        pure
        returns (bytes memory)
    {
        bytes memory tempBytes;

        assembly {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
            tempBytes := mload(0x40)

            // Store the length of the first bytes array at the beginning of
            // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            // Maintain a memory counter for the current write location in the
            // temp bytes array by adding the 32 bytes for the array length to
            // the starting location.
            let mc := add(tempBytes, 0x20)
            // Stop copying when the memory counter reaches the length of the
            // first bytes array.
            let end := add(mc, length)

            for {
                // Initialize a copy counter to the start of the _preBytes data,
                // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                // Write the _preBytes data into the tempBytes memory 32 bytes
                // at a time.
                mstore(mc, mload(cc))
            }

            // Add the length of _postBytes to the current length of tempBytes
            // and store it as the new length in the first 32 bytes of the
            // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            // Move the memory counter back from a multiple of 0x20 to the
            // actual end of the _preBytes data.
            mc := end
            // Stop copying when the memory counter reaches the new combined
            // length of the arrays.
            end := add(mc, length)

            for {
                let cc := add(_postBytes, 0x20)
            } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                mstore(mc, mload(cc))
            }

            // Update the free-memory pointer by padding our last write location
            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
            // next 32 byte block, then round down to the nearest multiple of
            // 32. If the sum of the length of the two arrays is zero then add
            // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(0x40, and(
              add(add(end, iszero(add(length, mload(_preBytes)))), 31),
              not(31) // Round down to the nearest 32 bytes.
            ))
        }

        return tempBytes;
    }

    function slice(
        bytes memory _bytes,
        uint _start,
        uint _length
    )
        internal
        pure
        returns (bytes memory)
    {
        require(_bytes.length >= (_start + _length));

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint _start) internal  pure returns (address) {
        require(_bytes.length >= (_start + 20));
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint _start) internal  pure returns (uint8) {
        require(_bytes.length >= (_start + 1));
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint _start) internal  pure returns (uint16) {
        require(_bytes.length >= (_start + 2));
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint24(bytes memory _bytes, uint _start) internal  pure returns (uint24) {
        require(_bytes.length >= (_start + 3));
        uint24 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x3), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint _start) internal  pure returns (uint32) {
        require(_bytes.length >= (_start + 4));
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint _start) internal  pure returns (uint64) {
        require(_bytes.length >= (_start + 8));
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint _start) internal  pure returns (uint96) {
        require(_bytes.length >= (_start + 12));
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint _start) internal  pure returns (uint128) {
        require(_bytes.length >= (_start + 16));
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint(bytes memory _bytes, uint _start) internal  pure returns (uint256) {
        require(_bytes.length >= (_start + 32));
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes4(bytes memory _bytes, uint _start) internal  pure returns (bytes4) {
        require(_bytes.length >= (_start + 4));
        bytes4 tempBytes4;

        assembly {
            tempBytes4 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes4;
    }

    function toBytes20(bytes memory _bytes, uint _start) internal  pure returns (bytes20) {
        require(_bytes.length >= (_start + 20));
        bytes20 tempBytes20;

        assembly {
            tempBytes20 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes20;
    }

    function toBytes32(bytes memory _bytes, uint _start) internal  pure returns (bytes32) {
        require(_bytes.length >= (_start + 32));
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }


    function toAddressUnsafe(bytes memory _bytes, uint _start) internal  pure returns (address) {
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8Unsafe(bytes memory _bytes, uint _start) internal  pure returns (uint8) {
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16Unsafe(bytes memory _bytes, uint _start) internal  pure returns (uint16) {
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint24Unsafe(bytes memory _bytes, uint _start) internal  pure returns (uint24) {
        uint24 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x3), _start))
        }

        return tempUint;
    }

    function toUint32Unsafe(bytes memory _bytes, uint _start) internal  pure returns (uint32) {
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64Unsafe(bytes memory _bytes, uint _start) internal  pure returns (uint64) {
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96Unsafe(bytes memory _bytes, uint _start) internal  pure returns (uint96) {
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128Unsafe(bytes memory _bytes, uint _start) internal  pure returns (uint128) {
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUintUnsafe(bytes memory _bytes, uint _start) internal  pure returns (uint256) {
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes4Unsafe(bytes memory _bytes, uint _start) internal  pure returns (bytes4) {
        bytes4 tempBytes4;

        assembly {
            tempBytes4 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes4;
    }

    function toBytes20Unsafe(bytes memory _bytes, uint _start) internal  pure returns (bytes20) {
        bytes20 tempBytes20;

        assembly {
            tempBytes20 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes20;
    }

    function toBytes32Unsafe(bytes memory _bytes, uint _start) internal  pure returns (bytes32) {
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }


    function fastSHA256(
        bytes memory data
        )
        internal
        view
        returns (bytes32)
    {
        bytes32[] memory result = new bytes32[](1);
        bool success;
        assembly {
             let ptr := add(data, 32)
             success := staticcall(sub(gas(), 2000), 2, ptr, mload(data), add(result, 32), 32)
        }
        require(success, "SHA256_FAILED");
        return result[0];
    }
}

// File: contracts/core/iface/IAgentRegistry.sol

// Copyright 2017 Loopring Technology Limited.

interface IAgent{}

abstract contract IAgentRegistry
{
    /// @dev Returns whether an agent address is an agent of an account owner
    /// @param owner The account owner.
    /// @param agent The agent address
    /// @return True if the agent address is an agent for the account owner, else false
    function isAgent(
        address owner,
        address agent
        )
        external
        virtual
        view
        returns (bool);

    /// @dev Returns whether an agent address is an agent of all account owners
    /// @param owners The account owners.
    /// @param agent The agent address
    /// @return True if the agent address is an agent for the account owner, else false
    function isAgent(
        address[] calldata owners,
        address            agent
        )
        external
        virtual
        view
        returns (bool);

    /// @dev Returns whether an agent address is a universal agent.
    /// @param agent The agent address
    /// @return True if the agent address is a universal agent, else false
    function isUniversalAgent(address agent)
        public
        virtual
        view
        returns (bool);
}

// File: contracts/lib/Ownable.sol

// Copyright 2017 Loopring Technology Limited.


/// @title Ownable
/// @author Brecht Devos - <[email protected]>
/// @dev The Ownable contract has an owner address, and provides basic
///      authorization control functions, this simplifies the implementation of
///      "user permissions".
contract Ownable
{
    address public owner;

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

    /// @dev The Ownable constructor sets the original `owner` of the contract
    ///      to the sender.
    constructor()
    {
        owner = msg.sender;
    }

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

    /// @dev Allows the current owner to transfer control of the contract to a
    ///      new owner.
    /// @param newOwner The address to transfer ownership to.
    function transferOwnership(
        address newOwner
        )
        public
        virtual
        onlyOwner
    {
        require(newOwner != address(0), "ZERO_ADDRESS");
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

    function renounceOwnership()
        public
        onlyOwner
    {
        emit OwnershipTransferred(owner, address(0));
        owner = address(0);
    }
}

// File: contracts/lib/Claimable.sol

// Copyright 2017 Loopring Technology Limited.



/// @title Claimable
/// @author Brecht Devos - <[email protected]>
/// @dev Extension for the Ownable contract, where the ownership needs
///      to be claimed. This allows the new owner to accept the transfer.
contract Claimable is Ownable
{
    address public pendingOwner;

    /// @dev Modifier throws if called by any account other than the pendingOwner.
    modifier onlyPendingOwner() {
        require(msg.sender == pendingOwner, "UNAUTHORIZED");
        _;
    }

    /// @dev Allows the current owner to set the pendingOwner address.
    /// @param newOwner The address to transfer ownership to.
    function transferOwnership(
        address newOwner
        )
        public
        override
        onlyOwner
    {
        require(newOwner != address(0) && newOwner != owner, "INVALID_ADDRESS");
        pendingOwner = newOwner;
    }

    /// @dev Allows the pendingOwner address to finalize the transfer.
    function claimOwnership()
        public
        onlyPendingOwner
    {
        emit OwnershipTransferred(owner, pendingOwner);
        owner = pendingOwner;
        pendingOwner = address(0);
    }
}

// File: contracts/core/iface/IBlockVerifier.sol

// Copyright 2017 Loopring Technology Limited.



/// @title IBlockVerifier
/// @author Brecht Devos - <[email protected]>
abstract contract IBlockVerifier is Claimable
{
    // -- Events --

    event CircuitRegistered(
        uint8  indexed blockType,
        uint16         blockSize,
        uint8          blockVersion
    );

    event CircuitDisabled(
        uint8  indexed blockType,
        uint16         blockSize,
        uint8          blockVersion
    );

    // -- Public functions --

    /// @dev Sets the verifying key for the specified circuit.
    ///      Every block permutation needs its own circuit and thus its own set of
    ///      verification keys. Only a limited number of block sizes per block
    ///      type are supported.
    /// @param blockType The type of the block
    /// @param blockSize The number of requests handled in the block
    /// @param blockVersion The block version (i.e. which circuit version needs to be used)
    /// @param vk The verification key
    function registerCircuit(
        uint8    blockType,
        uint16   blockSize,
        uint8    blockVersion,
        uint[18] calldata vk
        )
        external
        virtual;

    /// @dev Disables the use of the specified circuit.
    /// @param blockType The type of the block
    /// @param blockSize The number of requests handled in the block
    /// @param blockVersion The block version (i.e. which circuit version needs to be used)
    function disableCircuit(
        uint8  blockType,
        uint16 blockSize,
        uint8  blockVersion
        )
        external
        virtual;

    /// @dev Verifies blocks with the given public data and proofs.
    ///      Verifying a block makes sure all requests handled in the block
    ///      are correctly handled by the operator.
    /// @param blockType The type of block
    /// @param blockSize The number of requests handled in the block
    /// @param blockVersion The block version (i.e. which circuit version needs to be used)
    /// @param publicInputs The hash of all the public data of the blocks
    /// @param proofs The ZK proofs proving that the blocks are correct
    /// @return True if the block is valid, false otherwise
    function verifyProofs(
        uint8  blockType,
        uint16 blockSize,
        uint8  blockVersion,
        uint[] calldata publicInputs,
        uint[] calldata proofs
        )
        external
        virtual
        view
        returns (bool);

    /// @dev Checks if a circuit with the specified parameters is registered.
    /// @param blockType The type of the block
    /// @param blockSize The number of requests handled in the block
    /// @param blockVersion The block version (i.e. which circuit version needs to be used)
    /// @return True if the circuit is registered, false otherwise
    function isCircuitRegistered(
        uint8  blockType,
        uint16 blockSize,
        uint8  blockVersion
        )
        external
        virtual
        view
        returns (bool);

    /// @dev Checks if a circuit can still be used to commit new blocks.
    /// @param blockType The type of the block
    /// @param blockSize The number of requests handled in the block
    /// @param blockVersion The block version (i.e. which circuit version needs to be used)
    /// @return True if the circuit is enabled, false otherwise
    function isCircuitEnabled(
        uint8  blockType,
        uint16 blockSize,
        uint8  blockVersion
        )
        external
        virtual
        view
        returns (bool);
}

// File: contracts/core/iface/IDepositContract.sol

// Copyright 2017 Loopring Technology Limited.


/// @title IDepositContract.
/// @dev   Contract storing and transferring funds for an exchange.
///
///        ERC1155 tokens can be supported by registering pseudo token addresses calculated
///        as `address(keccak256(real_token_address, token_params))`. Then the custom
///        deposit contract can look up the real token address and paramsters with the
///        pseudo token address before doing the transfers.
/// @author Brecht Devos - <[email protected]>
interface IDepositContract
{
    /// @dev Returns if a token is suppoprted by this contract.
    function isTokenSupported(address token)
        external
        view
        returns (bool);

    /// @dev Transfers tokens from a user to the exchange. This function will
    ///      be called when a user deposits funds to the exchange.
    ///      In a simple implementation the funds are simply stored inside the
    ///      deposit contract directly. More advanced implementations may store the funds
    ///      in some DeFi application to earn interest, so this function could directly
    ///      call the necessary functions to store the funds there.
    ///
    ///      This function needs to throw when an error occurred!
    ///
    ///      This function can only be called by the exchange.
    ///
    /// @param from The address of the account that sends the tokens.
    /// @param token The address of the token to transfer (`0x0` for ETH).
    /// @param amount The amount of tokens to transfer.
    /// @param extraData Opaque data that can be used by the contract to handle the deposit
    /// @return amountReceived The amount to deposit to the user's account in the Merkle tree
    function deposit(
        address from,
        address token,
        uint96  amount,
        bytes   calldata extraData
        )
        external
        payable
        returns (uint96 amountReceived);

    /// @dev Transfers tokens from the exchange to a user. This function will
    ///      be called when a withdrawal is done for a user on the exchange.
    ///      In the simplest implementation the funds are simply stored inside the
    ///      deposit contract directly so this simply transfers the requested tokens back
    ///      to the user. More advanced implementations may store the funds
    ///      in some DeFi application to earn interest so the function would
    ///      need to get those tokens back from the DeFi application first before they
    ///      can be transferred to the user.
    ///
    ///      This function needs to throw when an error occurred!
    ///
    ///      This function can only be called by the exchange.
    ///
    /// @param from The address from which 'amount' tokens are transferred.
    /// @param to The address to which 'amount' tokens are transferred.
    /// @param token The address of the token to transfer (`0x0` for ETH).
    /// @param amount The amount of tokens transferred.
    /// @param extraData Opaque data that can be used by the contract to handle the withdrawal
    function withdraw(
        address from,
        address to,
        address token,
        uint    amount,
        bytes   calldata extraData
        )
        external
        payable;

    /// @dev Transfers tokens (ETH not supported) for a user using the allowance set
    ///      for the exchange. This way the approval can be used for all functionality (and
    ///      extended functionality) of the exchange.
    ///      Should NOT be used to deposit/withdraw user funds, `deposit`/`withdraw`
    ///      should be used for that as they will contain specialised logic for those operations.
    ///      This function can be called by the exchange to transfer onchain funds of users
    ///      necessary for Agent functionality.
    ///
    ///      This function needs to throw when an error occurred!
    ///
    ///      This function can only be called by the exchange.
    ///
    /// @param from The address of the account that sends the tokens.
    /// @param to The address to which 'amount' tokens are transferred.
    /// @param token The address of the token to transfer (ETH is and cannot be suppported).
    /// @param amount The amount of tokens transferred.
    function transfer(
        address from,
        address to,
        address token,
        uint    amount
        )
        external
        payable;

    /// @dev Checks if the given address is used for depositing ETH or not.
    ///      Is used while depositing to send the correct ETH amount to the deposit contract.
    ///
    ///      Note that 0x0 is always registered for deposting ETH when the exchange is created!
    ///      This function allows additional addresses to be used for depositing ETH, the deposit
    ///      contract can implement different behaviour based on the address value.
    ///
    /// @param addr The address to check
    /// @return True if the address is used for depositing ETH, else false.
    function isETH(address addr)
        external
        view
        returns (bool);
}

// File: contracts/core/iface/ILoopringV3.sol

// Copyright 2017 Loopring Technology Limited.



/// @title ILoopringV3
/// @author Brecht Devos - <[email protected]>
/// @author Daniel Wang  - <[email protected]>
abstract contract ILoopringV3 is Claimable
{
    // == Events ==
    event ExchangeStakeDeposited(address exchangeAddr, uint amount);
    event ExchangeStakeWithdrawn(address exchangeAddr, uint amount);
    event ExchangeStakeBurned(address exchangeAddr, uint amount);
    event SettingsUpdated(uint time);

    // == Public Variables ==
    mapping (address => uint) internal exchangeStake;

    uint    public totalStake;
    address public blockVerifierAddress;
    uint    public forcedWithdrawalFee;
    uint    public tokenRegistrationFeeLRCBase;
    uint    public tokenRegistrationFeeLRCDelta;
    uint8   public protocolTakerFeeBips;
    uint8   public protocolMakerFeeBips;

    address payable public protocolFeeVault;

    // == Public Functions ==

    /// @dev Returns the LRC token address
    /// @return the LRC token address
    function lrcAddress()
        external
        view
        virtual
        returns (address);

    /// @dev Updates the global exchange settings.
    ///      This function can only be called by the owner of this contract.
    ///
    ///      Warning: these new values will be used by existing and
    ///      new Loopring exchanges.
    function updateSettings(
        address payable _protocolFeeVault,   // address(0) not allowed
        address _blockVerifierAddress,       // address(0) not allowed
        uint    _forcedWithdrawalFee
        )
        external
        virtual;

    /// @dev Updates the global protocol fee settings.
    ///      This function can only be called by the owner of this contract.
    ///
    ///      Warning: these new values will be used by existing and
    ///      new Loopring exchanges.
    function updateProtocolFeeSettings(
        uint8 _protocolTakerFeeBips,
        uint8 _protocolMakerFeeBips
        )
        external
        virtual;

    /// @dev Gets the amount of staked LRC for an exchange.
    /// @param exchangeAddr The address of the exchange
    /// @return stakedLRC The amount of LRC
    function getExchangeStake(
        address exchangeAddr
        )
        public
        virtual
        view
        returns (uint stakedLRC);

    /// @dev Burns a certain amount of staked LRC for a specific exchange.
    ///      This function is meant to be called only from exchange contracts.
    /// @return burnedLRC The amount of LRC burned. If the amount is greater than
    ///         the staked amount, all staked LRC will be burned.
    function burnExchangeStake(
        uint amount
        )
        external
        virtual
        returns (uint burnedLRC);

    /// @dev Stakes more LRC for an exchange.
    /// @param  exchangeAddr The address of the exchange
    /// @param  amountLRC The amount of LRC to stake
    /// @return stakedLRC The total amount of LRC staked for the exchange
    function depositExchangeStake(
        address exchangeAddr,
        uint    amountLRC
        )
        external
        virtual
        returns (uint stakedLRC);

    /// @dev Withdraws a certain amount of staked LRC for an exchange to the given address.
    ///      This function is meant to be called only from within exchange contracts.
    /// @param  recipient The address to receive LRC
    /// @param  requestedAmount The amount of LRC to withdraw
    /// @return amountLRC The amount of LRC withdrawn
    function withdrawExchangeStake(
        address recipient,
        uint    requestedAmount
        )
        external
        virtual
        returns (uint amountLRC);

    /// @dev Gets the protocol fee values for an exchange.
    /// @return takerFeeBips The protocol taker fee
    /// @return makerFeeBips The protocol maker fee
    function getProtocolFeeValues(
        )
        public
        virtual
        view
        returns (
            uint8 takerFeeBips,
            uint8 makerFeeBips
        );
}

// File: contracts/core/iface/ExchangeData.sol

// Copyright 2017 Loopring Technology Limited.






/// @title ExchangeData
/// @dev All methods in this lib are internal, therefore, there is no need
///      to deploy this library independently.
/// @author Daniel Wang  - <[email protected]>
/// @author Brecht Devos - <[email protected]>
library ExchangeData
{
    // -- Enums --
    enum TransactionType
    {
        NOOP,
        DEPOSIT,
        WITHDRAWAL,
        TRANSFER,
        SPOT_TRADE,
        ACCOUNT_UPDATE,
        AMM_UPDATE,
        SIGNATURE_VERIFICATION,
        NFT_MINT, // L2 NFT mint or L1-to-L2 NFT deposit
        NFT_DATA
    }

    enum NftType
    {
        ERC1155,
        ERC721
    }

    // -- Structs --
    struct Token
    {
        address token;
    }

    struct ProtocolFeeData
    {
        uint32 syncedAt; // only valid before 2105 (85 years to go)
        uint8  takerFeeBips;
        uint8  makerFeeBips;
        uint8  previousTakerFeeBips;
        uint8  previousMakerFeeBips;
    }

    // General auxiliary data for each conditional transaction
    struct AuxiliaryData
    {
        uint  txIndex;
        bool  approved;
        bytes data;
    }

    // This is the (virtual) block the owner  needs to submit onchain to maintain the
    // per-exchange (virtual) blockchain.
    struct Block
    {
        uint8      blockType;
        uint16     blockSize;
        uint8      blockVersion;
        bytes      data;
        uint256[8] proof;

        // Whether we should store the @BlockInfo for this block on-chain.
        bool storeBlockInfoOnchain;

        // Block specific data that is only used to help process the block on-chain.
        // It is not used as input for the circuits and it is not necessary for data-availability.
        // This bytes array contains the abi encoded AuxiliaryData[] data.
        bytes auxiliaryData;

        // Arbitrary data, mainly for off-chain data-availability, i.e.,
        // the multihash of the IPFS file that contains the block data.
        bytes offchainData;
    }

    struct BlockInfo
    {
        // The time the block was submitted on-chain.
        uint32  timestamp;
        // The public data hash of the block (the 28 most significant bytes).
        bytes28 blockDataHash;
    }

    // Represents an onchain deposit request.
    struct Deposit
    {
        uint96 amount;
        uint64 timestamp;
    }

    // A forced withdrawal request.
    // If the actual owner of the account initiated the request (we don't know who the owner is
    // at the time the request is being made) the full balance will be withdrawn.
    struct ForcedWithdrawal
    {
        address owner;
        uint64  timestamp;
    }

    struct Constants
    {
        uint SNARK_SCALAR_FIELD;
        uint MAX_OPEN_FORCED_REQUESTS;
        uint MAX_AGE_FORCED_REQUEST_UNTIL_WITHDRAW_MODE;
        uint TIMESTAMP_HALF_WINDOW_SIZE_IN_SECONDS;
        uint MAX_NUM_ACCOUNTS;
        uint MAX_NUM_TOKENS;
        uint MIN_AGE_PROTOCOL_FEES_UNTIL_UPDATED;
        uint MIN_TIME_IN_SHUTDOWN;
        uint TX_DATA_AVAILABILITY_SIZE;
        uint MAX_AGE_DEPOSIT_UNTIL_WITHDRAWABLE_UPPERBOUND;
    }

    // This is the prime number that is used for the alt_bn128 elliptic curve, see EIP-196.
    uint public constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;

    uint public constant MAX_OPEN_FORCED_REQUESTS = 4096;
    uint public constant MAX_AGE_FORCED_REQUEST_UNTIL_WITHDRAW_MODE = 15 days;
    uint public constant TIMESTAMP_HALF_WINDOW_SIZE_IN_SECONDS = 7 days;
    uint public constant MAX_NUM_ACCOUNTS = 2 ** 32;
    uint public constant MAX_NUM_TOKENS = 2 ** 16;
    uint public constant MIN_AGE_PROTOCOL_FEES_UNTIL_UPDATED = 7 days;
    uint public constant MIN_TIME_IN_SHUTDOWN = 30 days;
    // The amount of bytes each rollup transaction uses in the block data for data-availability.
    // This is the maximum amount of bytes of all different transaction types.
    uint32 public constant MAX_AGE_DEPOSIT_UNTIL_WITHDRAWABLE_UPPERBOUND = 15 days;
    uint32 public constant ACCOUNTID_PROTOCOLFEE = 0;

    uint public constant TX_DATA_AVAILABILITY_SIZE = 68;
    uint public constant TX_DATA_AVAILABILITY_SIZE_PART_1 = 29;
    uint public constant TX_DATA_AVAILABILITY_SIZE_PART_2 = 39;

    uint public constant NFT_TOKEN_ID_START = 2 ** 15;

    struct AccountLeaf
    {
        uint32   accountID;
        address  owner;
        uint     pubKeyX;
        uint     pubKeyY;
        uint32   nonce;
        uint     feeBipsAMM;
    }

    struct BalanceLeaf
    {
        uint16   tokenID;
        uint96   balance;
        uint     weightAMM;
        uint     storageRoot;
    }

    struct Nft
    {
        address minter;             // Minter address for a L2 mint or
                                    // the NFT's contract address in the case of a L1-to-L2 NFT deposit.
        NftType nftType;
        address token;
        uint256 nftID;
        uint8   creatorFeeBips;
    }

    struct MerkleProof
    {
        ExchangeData.AccountLeaf accountLeaf;
        ExchangeData.BalanceLeaf balanceLeaf;
        ExchangeData.Nft         nft;
        uint[48]                 accountMerkleProof;
        uint[24]                 balanceMerkleProof;
    }

    struct BlockContext
    {
        bytes32 DOMAIN_SEPARATOR;
        uint32  timestamp;
        Block   block;
        uint    txIndex;
    }

    // Represents the entire exchange state except the owner of the exchange.
    struct State
    {
        uint32  maxAgeDepositUntilWithdrawable;
        bytes32 DOMAIN_SEPARATOR;

        ILoopringV3      loopring;
        IBlockVerifier   blockVerifier;
        IAgentRegistry   agentRegistry;
        IDepositContract depositContract;


        // The merkle root of the offchain data stored in a Merkle tree. The Merkle tree
        // stores balances for users using an account model.
        bytes32 merkleRoot;

        // List of all blocks
        mapping(uint => BlockInfo) blocks;
        uint  numBlocks;

        // List of all tokens
        Token[] tokens;

        // A map from a token to its tokenID + 1
        mapping (address => uint16) tokenToTokenId;

        // A map from an accountID to a tokenID to if the balance is withdrawn
        mapping (uint32 => mapping (uint16 => bool)) withdrawnInWithdrawMode;

        // A map from an account to a token to the amount withdrawable for that account.
        // This is only used when the automatic distribution of the withdrawal failed.
        mapping (address => mapping (uint16 => uint)) amountWithdrawable;

        // A map from an account to a token to the forced withdrawal (always full balance)
        // The `uint16' represents ERC20 token ID (if < NFT_TOKEN_ID_START) or
        // NFT balance slot (if >= NFT_TOKEN_ID_START)
        mapping (uint32 => mapping (uint16 => ForcedWithdrawal)) pendingForcedWithdrawals;

        // A map from an address to a token to a deposit
        mapping (address => mapping (uint16 => Deposit)) pendingDeposits;

        // A map from an account owner to an approved transaction hash to if the transaction is approved or not
        mapping (address => mapping (bytes32 => bool)) approvedTx;

        // A map from an account owner to a destination address to a tokenID to an amount to a storageID to a new recipient address
        mapping (address => mapping (address => mapping (uint16 => mapping (uint => mapping (uint32 => address))))) withdrawalRecipient;


        // Counter to keep track of how many of forced requests are open so we can limit the work that needs to be done by the owner
        uint32 numPendingForcedTransactions;

        // Cached data for the protocol fee
        ProtocolFeeData protocolFeeData;

        // Time when the exchange was shutdown
        uint shutdownModeStartTime;

        // Time when the exchange has entered withdrawal mode
        uint withdrawalModeStartTime;

        // Last time the protocol fee was withdrawn for a specific token
        mapping (address => uint) protocolFeeLastWithdrawnTime;

        // Duplicated loopring address
        address loopringAddr;
        // AMM fee bips
        uint8   ammFeeBips;
        // Enable/Disable `onchainTransferFrom`
        bool    allowOnchainTransferFrom;

        // owner => NFT type => token address => nftID => Deposit
        mapping (address => mapping (NftType => mapping (address => mapping(uint256 => Deposit)))) pendingNFTDeposits;

        // owner => minter => NFT type => token address => nftID => amount withdrawable
        // This is only used when the automatic distribution of the withdrawal failed.
        mapping (address => mapping (address => mapping (NftType => mapping (address => mapping(uint256 => uint))))) amountWithdrawableNFT;
    }
}

// File: contracts/lib/MathUint.sol

// Copyright 2017 Loopring Technology Limited.


/// @title Utility Functions for uint
/// @author Daniel Wang - <[email protected]>
library MathUint
{
    using MathUint for uint;

    function mul(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint c)
    {
        c = a * b;
        require(a == 0 || c / a == b, "MUL_OVERFLOW");
    }

    function sub(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint)
    {
        require(b <= a, "SUB_UNDERFLOW");
        return a - b;
    }

    function add(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint c)
    {
        c = a + b;
        require(c >= a, "ADD_OVERFLOW");
    }

    function add64(
        uint64 a,
        uint64 b
        )
        internal
        pure
        returns (uint64 c)
    {
        c = a + b;
        require(c >= a, "ADD_OVERFLOW");
    }
}

// File: contracts/lib/Poseidon.sol

// Copyright 2017 Loopring Technology Limited.


/// @title Poseidon hash function
///        See: https://eprint.iacr.org/2019/458.pdf
///        Code auto-generated by generate_poseidon_EVM_code.py
/// @author Brecht Devos - <[email protected]>
library Poseidon
{
    //
    // hash_t4f6p52
    //

    struct HashInputs4
    {
        uint t0;
        uint t1;
        uint t2;
        uint t3;
    }

    function mix(HashInputs4 memory i, uint q) internal pure
    {
        HashInputs4 memory o;
        o.t0 = mulmod(i.t0, 11739432287187184656569880828944421268616385874806221589758215824904320817117, q);
        o.t0 = addmod(o.t0, mulmod(i.t1, 4977258759536702998522229302103997878600602264560359702680165243908162277980, q), q);
        o.t0 = addmod(o.t0, mulmod(i.t2, 19167410339349846567561662441069598364702008768579734801591448511131028229281, q), q);
        o.t0 = addmod(o.t0, mulmod(i.t3, 14183033936038168803360723133013092560869148726790180682363054735190196956789, q), q);
        o.t1 = mulmod(i.t0, 16872301185549870956030057498946148102848662396374401407323436343924021192350, q);
        o.t1 = addmod(o.t1, mulmod(i.t1, 107933704346764130067829474107909495889716688591997879426350582457782826785, q), q);
        o.t1 = addmod(o.t1, mulmod(i.t2, 17034139127218860091985397764514160131253018178110701196935786874261236172431, q), q);
        o.t1 = addmod(o.t1, mulmod(i.t3, 2799255644797227968811798608332314218966179365168250111693473252876996230317, q), q);
        o.t2 = mulmod(i.t0, 18618317300596756144100783409915332163189452886691331959651778092154775572832, q);
        o.t2 = addmod(o.t2, mulmod(i.t1, 13596762909635538739079656925495736900379091964739248298531655823337482778123, q), q);
        o.t2 = addmod(o.t2, mulmod(i.t2, 18985203040268814769637347880759846911264240088034262814847924884273017355969, q), q);
        o.t2 = addmod(o.t2, mulmod(i.t3, 8652975463545710606098548415650457376967119951977109072274595329619335974180, q), q);
        o.t3 = mulmod(i.t0, 11128168843135959720130031095451763561052380159981718940182755860433840154182, q);
        o.t3 = addmod(o.t3, mulmod(i.t1, 2953507793609469112222895633455544691298656192015062835263784675891831794974, q), q);
        o.t3 = addmod(o.t3, mulmod(i.t2, 19025623051770008118343718096455821045904242602531062247152770448380880817517, q), q);
        o.t3 = addmod(o.t3, mulmod(i.t3, 9077319817220936628089890431129759976815127354480867310384708941479362824016, q), q);
        i.t0 = o.t0;
        i.t1 = o.t1;
        i.t2 = o.t2;
        i.t3 = o.t3;
    }

    function ark(HashInputs4 memory i, uint q, uint c) internal pure
    {
        HashInputs4 memory o;
        o.t0 = addmod(i.t0, c, q);
        o.t1 = addmod(i.t1, c, q);
        o.t2 = addmod(i.t2, c, q);
        o.t3 = addmod(i.t3, c, q);
        i.t0 = o.t0;
        i.t1 = o.t1;
        i.t2 = o.t2;
        i.t3 = o.t3;
    }

    function sbox_full(HashInputs4 memory i, uint q) internal pure
    {
        HashInputs4 memory o;
        o.t0 = mulmod(i.t0, i.t0, q);
        o.t0 = mulmod(o.t0, o.t0, q);
        o.t0 = mulmod(i.t0, o.t0, q);
        o.t1 = mulmod(i.t1, i.t1, q);
        o.t1 = mulmod(o.t1, o.t1, q);
        o.t1 = mulmod(i.t1, o.t1, q);
        o.t2 = mulmod(i.t2, i.t2, q);
        o.t2 = mulmod(o.t2, o.t2, q);
        o.t2 = mulmod(i.t2, o.t2, q);
        o.t3 = mulmod(i.t3, i.t3, q);
        o.t3 = mulmod(o.t3, o.t3, q);
        o.t3 = mulmod(i.t3, o.t3, q);
        i.t0 = o.t0;
        i.t1 = o.t1;
        i.t2 = o.t2;
        i.t3 = o.t3;
    }

    function sbox_partial(HashInputs4 memory i, uint q) internal pure
    {
        HashInputs4 memory o;
        o.t0 = mulmod(i.t0, i.t0, q);
        o.t0 = mulmod(o.t0, o.t0, q);
        o.t0 = mulmod(i.t0, o.t0, q);
        i.t0 = o.t0;
    }

    function hash_t4f6p52(HashInputs4 memory i, uint q) internal pure returns (uint)
    {
        // validate inputs
        require(i.t0 < q, "INVALID_INPUT");
        require(i.t1 < q, "INVALID_INPUT");
        require(i.t2 < q, "INVALID_INPUT");
        require(i.t3 < q, "INVALID_INPUT");

        // round 0
        ark(i, q, 14397397413755236225575615486459253198602422701513067526754101844196324375522);
        sbox_full(i, q);
        mix(i, q);
        // round 1
        ark(i, q, 10405129301473404666785234951972711717481302463898292859783056520670200613128);
        sbox_full(i, q);
        mix(i, q);
        // round 2
        ark(i, q, 5179144822360023508491245509308555580251733042407187134628755730783052214509);
        sbox_full(i, q);
        mix(i, q);
        // round 3
        ark(i, q, 9132640374240188374542843306219594180154739721841249568925550236430986592615);
        sbox_partial(i, q);
        mix(i, q);
        // round 4
        ark(i, q, 20360807315276763881209958738450444293273549928693737723235350358403012458514);
        sbox_partial(i, q);
        mix(i, q);
        // round 5
        ark(i, q, 17933600965499023212689924809448543050840131883187652471064418452962948061619);
        sbox_partial(i, q);
        mix(i, q);
        // round 6
        ark(i, q, 3636213416533737411392076250708419981662897009810345015164671602334517041153);
        sbox_partial(i, q);
        mix(i, q);
        // round 7
        ark(i, q, 2008540005368330234524962342006691994500273283000229509835662097352946198608);
        sbox_partial(i, q);
        mix(i, q);
        // round 8
        ark(i, q, 16018407964853379535338740313053768402596521780991140819786560130595652651567);
        sbox_partial(i, q);
        mix(i, q);
        // round 9
        ark(i, q, 20653139667070586705378398435856186172195806027708437373983929336015162186471);
        sbox_partial(i, q);
        mix(i, q);
        // round 10
        ark(i, q, 17887713874711369695406927657694993484804203950786446055999405564652412116765);
        sbox_partial(i, q);
        mix(i, q);
        // round 11
        ark(i, q, 4852706232225925756777361208698488277369799648067343227630786518486608711772);
        sbox_partial(i, q);
        mix(i, q);
        // round 12
        ark(i, q, 8969172011633935669771678412400911310465619639756845342775631896478908389850);
        sbox_partial(i, q);
        mix(i, q);
        // round 13
        ark(i, q, 20570199545627577691240476121888846460936245025392381957866134167601058684375);
        sbox_partial(i, q);
        mix(i, q);
        // round 14
        ark(i, q, 16442329894745639881165035015179028112772410105963688121820543219662832524136);
        sbox_partial(i, q);
        mix(i, q);
        // round 15
        ark(i, q, 20060625627350485876280451423010593928172611031611836167979515653463693899374);
        sbox_partial(i, q);
        mix(i, q);
        // round 16
        ark(i, q, 16637282689940520290130302519163090147511023430395200895953984829546679599107);
        sbox_partial(i, q);
        mix(i, q);
        // round 17
        ark(i, q, 15599196921909732993082127725908821049411366914683565306060493533569088698214);
        sbox_partial(i, q);
        mix(i, q);
        // round 18
        ark(i, q, 16894591341213863947423904025624185991098788054337051624251730868231322135455);
        sbox_partial(i, q);
        mix(i, q);
        // round 19
        ark(i, q, 1197934381747032348421303489683932612752526046745577259575778515005162320212);
        sbox_partial(i, q);
        mix(i, q);
        // round 20
        ark(i, q, 6172482022646932735745595886795230725225293469762393889050804649558459236626);
        sbox_partial(i, q);
        mix(i, q);
        // round 21
        ark(i, q, 21004037394166516054140386756510609698837211370585899203851827276330669555417);
        sbox_partial(i, q);
        mix(i, q);
        // round 22
        ark(i, q, 15262034989144652068456967541137853724140836132717012646544737680069032573006);
        sbox_partial(i, q);
        mix(i, q);
        // round 23
        ark(i, q, 15017690682054366744270630371095785995296470601172793770224691982518041139766);
        sbox_partial(i, q);
        mix(i, q);
        // round 24
        ark(i, q, 15159744167842240513848638419303545693472533086570469712794583342699782519832);
        sbox_partial(i, q);
        mix(i, q);
        // round 25
        ark(i, q, 11178069035565459212220861899558526502477231302924961773582350246646450941231);
        sbox_partial(i, q);
        mix(i, q);
        // round 26
        ark(i, q, 21154888769130549957415912997229564077486639529994598560737238811887296922114);
        sbox_partial(i, q);
        mix(i, q);
        // round 27
        ark(i, q, 20162517328110570500010831422938033120419484532231241180224283481905744633719);
        sbox_partial(i, q);
        mix(i, q);
        // round 28
        ark(i, q, 2777362604871784250419758188173029886707024739806641263170345377816177052018);
        sbox_partial(i, q);
        mix(i, q);
        // round 29
        ark(i, q, 15732290486829619144634131656503993123618032247178179298922551820261215487562);
        sbox_partial(i, q);
        mix(i, q);
        // round 30
        ark(i, q, 6024433414579583476444635447152826813568595303270846875177844482142230009826);
        sbox_partial(i, q);
        mix(i, q);
        // round 31
        ark(i, q, 17677827682004946431939402157761289497221048154630238117709539216286149983245);
        sbox_partial(i, q);
        mix(i, q);
        // round 32
        ark(i, q, 10716307389353583413755237303156291454109852751296156900963208377067748518748);
        sbox_partial(i, q);
        mix(i, q);
        // round 33
        ark(i, q, 14925386988604173087143546225719076187055229908444910452781922028996524347508);
        sbox_partial(i, q);
        mix(i, q);
        // round 34
        ark(i, q, 8940878636401797005293482068100797531020505636124892198091491586778667442523);
        sbox_partial(i, q);
        mix(i, q);
        // round 35
        ark(i, q, 18911747154199663060505302806894425160044925686870165583944475880789706164410);
        sbox_partial(i, q);
        mix(i, q);
        // round 36
        ark(i, q, 8821532432394939099312235292271438180996556457308429936910969094255825456935);
        sbox_partial(i, q);
        mix(i, q);
        // round 37
        ark(i, q, 20632576502437623790366878538516326728436616723089049415538037018093616927643);
        sbox_partial(i, q);
        mix(i, q);
        // round 38
        ark(i, q, 71447649211767888770311304010816315780740050029903404046389165015534756512);
        sbox_partial(i, q);
        mix(i, q);
        // round 39
        ark(i, q, 2781996465394730190470582631099299305677291329609718650018200531245670229393);
        sbox_partial(i, q);
        mix(i, q);
        // round 40
        ark(i, q, 12441376330954323535872906380510501637773629931719508864016287320488688345525);
        sbox_partial(i, q);
        mix(i, q);
        // round 41
        ark(i, q, 2558302139544901035700544058046419714227464650146159803703499681139469546006);
        sbox_partial(i, q);
        mix(i, q);
        // round 42
        ark(i, q, 10087036781939179132584550273563255199577525914374285705149349445480649057058);
        sbox_partial(i, q);
        mix(i, q);
        // round 43
        ark(i, q, 4267692623754666261749551533667592242661271409704769363166965280715887854739);
        sbox_partial(i, q);
        mix(i, q);
        // round 44
        ark(i, q, 4945579503584457514844595640661884835097077318604083061152997449742124905548);
        sbox_partial(i, q);
        mix(i, q);
        // round 45
        ark(i, q, 17742335354489274412669987990603079185096280484072783973732137326144230832311);
        sbox_partial(i, q);
        mix(i, q);
        // round 46
        ark(i, q, 6266270088302506215402996795500854910256503071464802875821837403486057988208);
        sbox_partial(i, q);
        mix(i, q);
        // round 47
        ark(i, q, 2716062168542520412498610856550519519760063668165561277991771577403400784706);
        sbox_partial(i, q);
        mix(i, q);
        // round 48
        ark(i, q, 19118392018538203167410421493487769944462015419023083813301166096764262134232);
        sbox_partial(i, q);
        mix(i, q);
        // round 49
        ark(i, q, 9386595745626044000666050847309903206827901310677406022353307960932745699524);
        sbox_partial(i, q);
        mix(i, q);
        // round 50
        ark(i, q, 9121640807890366356465620448383131419933298563527245687958865317869840082266);
        sbox_partial(i, q);
        mix(i, q);
        // round 51
        ark(i, q, 3078975275808111706229899605611544294904276390490742680006005661017864583210);
        sbox_partial(i, q);
        mix(i, q);
        // round 52
        ark(i, q, 7157404299437167354719786626667769956233708887934477609633504801472827442743);
        sbox_partial(i, q);
        mix(i, q);
        // round 53
        ark(i, q, 14056248655941725362944552761799461694550787028230120190862133165195793034373);
        sbox_partial(i, q);
        mix(i, q);
        // round 54
        ark(i, q, 14124396743304355958915937804966111851843703158171757752158388556919187839849);
        sbox_partial(i, q);
        mix(i, q);
        // round 55
        ark(i, q, 11851254356749068692552943732920045260402277343008629727465773766468466181076);
        sbox_full(i, q);
        mix(i, q);
        // round 56
        ark(i, q, 9799099446406796696742256539758943483211846559715874347178722060519817626047);
        sbox_full(i, q);
        mix(i, q);
        // round 57
        ark(i, q, 10156146186214948683880719664738535455146137901666656566575307300522957959544);
        sbox_full(i, q);
        mix(i, q);

        return i.t0;
    }


    //
    // hash_t5f6p52
    //

    struct HashInputs5
    {
        uint t0;
        uint t1;
        uint t2;
        uint t3;
        uint t4;
    }

    function hash_t5f6p52_internal(
        uint t0,
        uint t1,
        uint t2,
        uint t3,
        uint t4,
        uint q
        )
        internal
        pure
        returns (uint)
    {
        assembly {
            function mix(_t0, _t1, _t2, _t3, _t4, _q) -> nt0, nt1, nt2, nt3, nt4 {
                nt0 := mulmod(_t0, 4977258759536702998522229302103997878600602264560359702680165243908162277980, _q)
                nt0 := addmod(nt0, mulmod(_t1, 19167410339349846567561662441069598364702008768579734801591448511131028229281, _q), _q)
                nt0 := addmod(nt0, mulmod(_t2, 14183033936038168803360723133013092560869148726790180682363054735190196956789, _q), _q)
                nt0 := addmod(nt0, mulmod(_t3, 9067734253445064890734144122526450279189023719890032859456830213166173619761, _q), _q)
                nt0 := addmod(nt0, mulmod(_t4, 16378664841697311562845443097199265623838619398287411428110917414833007677155, _q), _q)
                nt1 := mulmod(_t0, 107933704346764130067829474107909495889716688591997879426350582457782826785, _q)
                nt1 := addmod(nt1, mulmod(_t1, 17034139127218860091985397764514160131253018178110701196935786874261236172431, _q), _q)
                nt1 := addmod(nt1, mulmod(_t2, 2799255644797227968811798608332314218966179365168250111693473252876996230317, _q), _q)
                nt1 := addmod(nt1, mulmod(_t3, 2482058150180648511543788012634934806465808146786082148795902594096349483974, _q), _q)
                nt1 := addmod(nt1, mulmod(_t4, 16563522740626180338295201738437974404892092704059676533096069531044355099628, _q), _q)
                nt2 := mulmod(_t0, 13596762909635538739079656925495736900379091964739248298531655823337482778123, _q)
                nt2 := addmod(nt2, mulmod(_t1, 18985203040268814769637347880759846911264240088034262814847924884273017355969, _q), _q)
                nt2 := addmod(nt2, mulmod(_t2, 8652975463545710606098548415650457376967119951977109072274595329619335974180, _q), _q)
                nt2 := addmod(nt2, mulmod(_t3, 970943815872417895015626519859542525373809485973005165410533315057253476903, _q), _q)
                nt2 := addmod(nt2, mulmod(_t4, 19406667490568134101658669326517700199745817783746545889094238643063688871948, _q), _q)
                nt3 := mulmod(_t0, 2953507793609469112222895633455544691298656192015062835263784675891831794974, _q)
                nt3 := addmod(nt3, mulmod(_t1, 19025623051770008118343718096455821045904242602531062247152770448380880817517, _q), _q)
                nt3 := addmod(nt3, mulmod(_t2, 9077319817220936628089890431129759976815127354480867310384708941479362824016, _q), _q)
                nt3 := addmod(nt3, mulmod(_t3, 4770370314098695913091200576539533727214143013236894216582648993741910829490, _q), _q)
                nt3 := addmod(nt3, mulmod(_t4, 4298564056297802123194408918029088169104276109138370115401819933600955259473, _q), _q)
                nt4 := mulmod(_t0, 8336710468787894148066071988103915091676109272951895469087957569358494947747, _q)
                nt4 := addmod(nt4, mulmod(_t1, 16205238342129310687768799056463408647672389183328001070715567975181364448609, _q), _q)
                nt4 := addmod(nt4, mulmod(_t2, 8303849270045876854140023508764676765932043944545416856530551331270859502246, _q), _q)
                nt4 := addmod(nt4, mulmod(_t3, 20218246699596954048529384569730026273241102596326201163062133863539137060414, _q), _q)
                nt4 := addmod(nt4, mulmod(_t4, 1712845821388089905746651754894206522004527237615042226559791118162382909269, _q), _q)
            }

            function ark(_t0, _t1, _t2, _t3, _t4, _q, c) -> nt0, nt1, nt2, nt3, nt4 {
                nt0 := addmod(_t0, c, _q)
                nt1 := addmod(_t1, c, _q)
                nt2 := addmod(_t2, c, _q)
                nt3 := addmod(_t3, c, _q)
                nt4 := addmod(_t4, c, _q)
            }

            function sbox_full(_t0, _t1, _t2, _t3, _t4, _q) -> nt0, nt1, nt2, nt3, nt4 {
                nt0 := mulmod(_t0, _t0, _q)
                nt0 := mulmod(nt0, nt0, _q)
                nt0 := mulmod(_t0, nt0, _q)
                nt1 := mulmod(_t1, _t1, _q)
                nt1 := mulmod(nt1, nt1, _q)
                nt1 := mulmod(_t1, nt1, _q)
                nt2 := mulmod(_t2, _t2, _q)
                nt2 := mulmod(nt2, nt2, _q)
                nt2 := mulmod(_t2, nt2, _q)
                nt3 := mulmod(_t3, _t3, _q)
                nt3 := mulmod(nt3, nt3, _q)
                nt3 := mulmod(_t3, nt3, _q)
                nt4 := mulmod(_t4, _t4, _q)
                nt4 := mulmod(nt4, nt4, _q)
                nt4 := mulmod(_t4, nt4, _q)
            }

            function sbox_partial(_t, _q) -> nt {
                nt := mulmod(_t, _t, _q)
                nt := mulmod(nt, nt, _q)
                nt := mulmod(_t, nt, _q)
            }

            // round 0
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 14397397413755236225575615486459253198602422701513067526754101844196324375522)
            t0, t1, t2, t3, t4 := sbox_full(t0, t1, t2, t3, t4, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 1
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 10405129301473404666785234951972711717481302463898292859783056520670200613128)
            t0, t1, t2, t3, t4 := sbox_full(t0, t1, t2, t3, t4, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 2
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 5179144822360023508491245509308555580251733042407187134628755730783052214509)
            t0, t1, t2, t3, t4 := sbox_full(t0, t1, t2, t3, t4, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 3
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 9132640374240188374542843306219594180154739721841249568925550236430986592615)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 4
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 20360807315276763881209958738450444293273549928693737723235350358403012458514)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 5
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 17933600965499023212689924809448543050840131883187652471064418452962948061619)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 6
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 3636213416533737411392076250708419981662897009810345015164671602334517041153)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 7
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 2008540005368330234524962342006691994500273283000229509835662097352946198608)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 8
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 16018407964853379535338740313053768402596521780991140819786560130595652651567)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 9
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 20653139667070586705378398435856186172195806027708437373983929336015162186471)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 10
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 17887713874711369695406927657694993484804203950786446055999405564652412116765)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 11
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 4852706232225925756777361208698488277369799648067343227630786518486608711772)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 12
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 8969172011633935669771678412400911310465619639756845342775631896478908389850)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 13
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 20570199545627577691240476121888846460936245025392381957866134167601058684375)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 14
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 16442329894745639881165035015179028112772410105963688121820543219662832524136)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 15
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 20060625627350485876280451423010593928172611031611836167979515653463693899374)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 16
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 16637282689940520290130302519163090147511023430395200895953984829546679599107)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 17
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 15599196921909732993082127725908821049411366914683565306060493533569088698214)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 18
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 16894591341213863947423904025624185991098788054337051624251730868231322135455)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 19
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 1197934381747032348421303489683932612752526046745577259575778515005162320212)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 20
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 6172482022646932735745595886795230725225293469762393889050804649558459236626)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 21
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 21004037394166516054140386756510609698837211370585899203851827276330669555417)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 22
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 15262034989144652068456967541137853724140836132717012646544737680069032573006)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 23
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 15017690682054366744270630371095785995296470601172793770224691982518041139766)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 24
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 15159744167842240513848638419303545693472533086570469712794583342699782519832)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 25
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 11178069035565459212220861899558526502477231302924961773582350246646450941231)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 26
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 21154888769130549957415912997229564077486639529994598560737238811887296922114)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 27
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 20162517328110570500010831422938033120419484532231241180224283481905744633719)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 28
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 2777362604871784250419758188173029886707024739806641263170345377816177052018)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 29
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 15732290486829619144634131656503993123618032247178179298922551820261215487562)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 30
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 6024433414579583476444635447152826813568595303270846875177844482142230009826)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 31
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 17677827682004946431939402157761289497221048154630238117709539216286149983245)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 32
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 10716307389353583413755237303156291454109852751296156900963208377067748518748)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 33
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 14925386988604173087143546225719076187055229908444910452781922028996524347508)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 34
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 8940878636401797005293482068100797531020505636124892198091491586778667442523)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 35
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 18911747154199663060505302806894425160044925686870165583944475880789706164410)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 36
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 8821532432394939099312235292271438180996556457308429936910969094255825456935)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 37
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 20632576502437623790366878538516326728436616723089049415538037018093616927643)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 38
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 71447649211767888770311304010816315780740050029903404046389165015534756512)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 39
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 2781996465394730190470582631099299305677291329609718650018200531245670229393)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 40
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 12441376330954323535872906380510501637773629931719508864016287320488688345525)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 41
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 2558302139544901035700544058046419714227464650146159803703499681139469546006)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 42
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 10087036781939179132584550273563255199577525914374285705149349445480649057058)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 43
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 4267692623754666261749551533667592242661271409704769363166965280715887854739)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 44
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 4945579503584457514844595640661884835097077318604083061152997449742124905548)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 45
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 17742335354489274412669987990603079185096280484072783973732137326144230832311)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 46
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 6266270088302506215402996795500854910256503071464802875821837403486057988208)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 47
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 2716062168542520412498610856550519519760063668165561277991771577403400784706)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 48
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 19118392018538203167410421493487769944462015419023083813301166096764262134232)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 49
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 9386595745626044000666050847309903206827901310677406022353307960932745699524)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 50
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 9121640807890366356465620448383131419933298563527245687958865317869840082266)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 51
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 3078975275808111706229899605611544294904276390490742680006005661017864583210)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 52
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 7157404299437167354719786626667769956233708887934477609633504801472827442743)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 53
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 14056248655941725362944552761799461694550787028230120190862133165195793034373)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 54
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 14124396743304355958915937804966111851843703158171757752158388556919187839849)
            t0 := sbox_partial(t0, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 55
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 11851254356749068692552943732920045260402277343008629727465773766468466181076)
            t0, t1, t2, t3, t4 := sbox_full(t0, t1, t2, t3, t4, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 56
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 9799099446406796696742256539758943483211846559715874347178722060519817626047)
            t0, t1, t2, t3, t4 := sbox_full(t0, t1, t2, t3, t4, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
            // round 57
            t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 10156146186214948683880719664738535455146137901666656566575307300522957959544)
            t0, t1, t2, t3, t4 := sbox_full(t0, t1, t2, t3, t4, q)
            t0, t1, t2, t3, t4 := mix(t0, t1, t2, t3, t4, q)
        }
        return t0;
    }

    function hash_t5f6p52(HashInputs5 memory i, uint q) internal pure returns (uint)
    {
        // validate inputs
        require(i.t0 < q, "INVALID_INPUT");
        require(i.t1 < q, "INVALID_INPUT");
        require(i.t2 < q, "INVALID_INPUT");
        require(i.t3 < q, "INVALID_INPUT");
        require(i.t4 < q, "INVALID_INPUT");

        return hash_t5f6p52_internal(i.t0, i.t1, i.t2, i.t3, i.t4, q);
    }


    //
    // hash_t7f6p52
    //

    struct HashInputs7
    {
        uint t0;
        uint t1;
        uint t2;
        uint t3;
        uint t4;
        uint t5;
        uint t6;
    }

    function mix(HashInputs7 memory i, uint q) internal pure
    {
        HashInputs7 memory o;
        o.t0 = mulmod(i.t0, 14183033936038168803360723133013092560869148726790180682363054735190196956789, q);
        o.t0 = addmod(o.t0, mulmod(i.t1, 9067734253445064890734144122526450279189023719890032859456830213166173619761, q), q);
        o.t0 = addmod(o.t0, mulmod(i.t2, 16378664841697311562845443097199265623838619398287411428110917414833007677155, q), q);
        o.t0 = addmod(o.t0, mulmod(i.t3, 12968540216479938138647596899147650021419273189336843725176422194136033835172, q), q);
        o.t0 = addmod(o.t0, mulmod(i.t4, 3636162562566338420490575570584278737093584021456168183289112789616069756675, q), q);
        o.t0 = addmod(o.t0, mulmod(i.t5, 8949952361235797771659501126471156178804092479420606597426318793013844305422, q), q);
        o.t0 = addmod(o.t0, mulmod(i.t6, 13586657904816433080148729258697725609063090799921401830545410130405357110367, q), q);
        o.t1 = mulmod(i.t0, 2799255644797227968811798608332314218966179365168250111693473252876996230317, q);
        o.t1 = addmod(o.t1, mulmod(i.t1, 2482058150180648511543788012634934806465808146786082148795902594096349483974, q), q);
        o.t1 = addmod(o.t1, mulmod(i.t2, 16563522740626180338295201738437974404892092704059676533096069531044355099628, q), q);
        o.t1 = addmod(o.t1, mulmod(i.t3, 10468644849657689537028565510142839489302836569811003546969773105463051947124, q), q);
        o.t1 = addmod(o.t1, mulmod(i.t4, 3328913364598498171733622353010907641674136720305714432354138807013088636408, q), q);
        o.t1 = addmod(o.t1, mulmod(i.t5, 8642889650254799419576843603477253661899356105675006557919250564400804756641, q), q);
        o.t1 = addmod(o.t1, mulmod(i.t6, 14300697791556510113764686242794463641010174685800128469053974698256194076125, q), q);
        o.t2 = mulmod(i.t0, 8652975463545710606098548415650457376967119951977109072274595329619335974180, q);
        o.t2 = addmod(o.t2, mulmod(i.t1, 970943815872417895015626519859542525373809485973005165410533315057253476903, q), q);
        o.t2 = addmod(o.t2, mulmod(i.t2, 19406667490568134101658669326517700199745817783746545889094238643063688871948, q), q);
        o.t2 = addmod(o.t2, mulmod(i.t3, 17049854690034965250221386317058877242629221002521630573756355118745574274967, q), q);
        o.t2 = addmod(o.t2, mulmod(i.t4, 4964394613021008685803675656098849539153699842663541444414978877928878266244, q), q);
        o.t2 = addmod(o.t2, mulmod(i.t5, 15474947305445649466370538888925567099067120578851553103424183520405650587995, q), q);
        o.t2 = addmod(o.t2, mulmod(i.t6, 1016119095639665978105768933448186152078842964810837543326777554729232767846, q), q);
        o.t3 = mulmod(i.t0, 9077319817220936628089890431129759976815127354480867310384708941479362824016, q);
        o.t3 = addmod(o.t3, mulmod(i.t1, 4770370314098695913091200576539533727214143013236894216582648993741910829490, q), q);
        o.t3 = addmod(o.t3, mulmod(i.t2, 4298564056297802123194408918029088169104276109138370115401819933600955259473, q), q);
        o.t3 = addmod(o.t3, mulmod(i.t3, 6905514380186323693285869145872115273350947784558995755916362330070690839131, q), q);
        o.t3 = addmod(o.t3, mulmod(i.t4, 4783343257810358393326889022942241108539824540285247795235499223017138301952, q), q);
        o.t3 = addmod(o.t3, mulmod(i.t5, 1420772902128122367335354247676760257656541121773854204774788519230732373317, q), q);
        o.t3 = addmod(o.t3, mulmod(i.t6, 14172871439045259377975734198064051992755748777535789572469924335100006948373, q), q);
        o.t4 = mulmod(i.t0, 8303849270045876854140023508764676765932043944545416856530551331270859502246, q);
        o.t4 = addmod(o.t4, mulmod(i.t1, 20218246699596954048529384569730026273241102596326201163062133863539137060414, q), q);
        o.t4 = addmod(o.t4, mulmod(i.t2, 1712845821388089905746651754894206522004527237615042226559791118162382909269, q), q);
        o.t4 = addmod(o.t4, mulmod(i.t3, 13001155522144542028910638547179410124467185319212645031214919884423841839406, q), q);
        o.t4 = addmod(o.t4, mulmod(i.t4, 16037892369576300958623292723740289861626299352695838577330319504984091062115, q), q);
        o.t4 = addmod(o.t4, mulmod(i.t5, 19189494548480259335554606182055502469831573298885662881571444557262020106898, q), q);
        o.t4 = addmod(o.t4, mulmod(i.t6, 19032687447778391106390582750185144485341165205399984747451318330476859342654, q), q);
        o.t5 = mulmod(i.t0, 13272957914179340594010910867091459756043436017766464331915862093201960540910, q);
        o.t5 = addmod(o.t5, mulmod(i.t1, 9416416589114508529880440146952102328470363729880726115521103179442988482948, q), q);
        o.t5 = addmod(o.t5, mulmod(i.t2, 8035240799672199706102747147502951589635001418759394863664434079699838251138, q), q);
        o.t5 = addmod(o.t5, mulmod(i.t3, 21642389080762222565487157652540372010968704000567605990102641816691459811717, q), q);
        o.t5 = addmod(o.t5, mulmod(i.t4, 20261355950827657195644012399234591122288573679402601053407151083849785332516, q), q);
        o.t5 = addmod(o.t5, mulmod(i.t5, 14514189384576734449268559374569145463190040567900950075547616936149781403109, q), q);
        o.t5 = addmod(o.t5, mulmod(i.t6, 19038036134886073991945204537416211699632292792787812530208911676638479944765, q), q);
        o.t6 = mulmod(i.t0, 15627836782263662543041758927100784213807648787083018234961118439434298020664, q);
        o.t6 = addmod(o.t6, mulmod(i.t1, 5655785191024506056588710805596292231240948371113351452712848652644610823632, q), q);
        o.t6 = addmod(o.t6, mulmod(i.t2, 8265264721707292643644260517162050867559314081394556886644673791575065394002, q), q);
        o.t6 = addmod(o.t6, mulmod(i.t3, 17151144681903609082202835646026478898625761142991787335302962548605510241586, q), q);
        o.t6 = addmod(o.t6, mulmod(i.t4, 18731644709777529787185361516475509623264209648904603914668024590231177708831, q), q);
        o.t6 = addmod(o.t6, mulmod(i.t5, 20697789991623248954020701081488146717484139720322034504511115160686216223641, q), q);
        o.t6 = addmod(o.t6, mulmod(i.t6, 6200020095464686209289974437830528853749866001482481427982839122465470640886, q), q);
        i.t0 = o.t0;
        i.t1 = o.t1;
        i.t2 = o.t2;
        i.t3 = o.t3;
        i.t4 = o.t4;
        i.t5 = o.t5;
        i.t6 = o.t6;
    }

    function ark(HashInputs7 memory i, uint q, uint c) internal pure
    {
        HashInputs7 memory o;
        o.t0 = addmod(i.t0, c, q);
        o.t1 = addmod(i.t1, c, q);
        o.t2 = addmod(i.t2, c, q);
        o.t3 = addmod(i.t3, c, q);
        o.t4 = addmod(i.t4, c, q);
        o.t5 = addmod(i.t5, c, q);
        o.t6 = addmod(i.t6, c, q);
        i.t0 = o.t0;
        i.t1 = o.t1;
        i.t2 = o.t2;
        i.t3 = o.t3;
        i.t4 = o.t4;
        i.t5 = o.t5;
        i.t6 = o.t6;
    }

    function sbox_full(HashInputs7 memory i, uint q) internal pure
    {
        HashInputs7 memory o;
        o.t0 = mulmod(i.t0, i.t0, q);
        o.t0 = mulmod(o.t0, o.t0, q);
        o.t0 = mulmod(i.t0, o.t0, q);
        o.t1 = mulmod(i.t1, i.t1, q);
        o.t1 = mulmod(o.t1, o.t1, q);
        o.t1 = mulmod(i.t1, o.t1, q);
        o.t2 = mulmod(i.t2, i.t2, q);
        o.t2 = mulmod(o.t2, o.t2, q);
        o.t2 = mulmod(i.t2, o.t2, q);
        o.t3 = mulmod(i.t3, i.t3, q);
        o.t3 = mulmod(o.t3, o.t3, q);
        o.t3 = mulmod(i.t3, o.t3, q);
        o.t4 = mulmod(i.t4, i.t4, q);
        o.t4 = mulmod(o.t4, o.t4, q);
        o.t4 = mulmod(i.t4, o.t4, q);
        o.t5 = mulmod(i.t5, i.t5, q);
        o.t5 = mulmod(o.t5, o.t5, q);
        o.t5 = mulmod(i.t5, o.t5, q);
        o.t6 = mulmod(i.t6, i.t6, q);
        o.t6 = mulmod(o.t6, o.t6, q);
        o.t6 = mulmod(i.t6, o.t6, q);
        i.t0 = o.t0;
        i.t1 = o.t1;
        i.t2 = o.t2;
        i.t3 = o.t3;
        i.t4 = o.t4;
        i.t5 = o.t5;
        i.t6 = o.t6;
    }

    function sbox_partial(HashInputs7 memory i, uint q) internal pure
    {
        HashInputs7 memory o;
        o.t0 = mulmod(i.t0, i.t0, q);
        o.t0 = mulmod(o.t0, o.t0, q);
        o.t0 = mulmod(i.t0, o.t0, q);
        i.t0 = o.t0;
    }

    function hash_t7f6p52(HashInputs7 memory i, uint q) internal pure returns (uint)
    {
        // validate inputs
        require(i.t0 < q, "INVALID_INPUT");
        require(i.t1 < q, "INVALID_INPUT");
        require(i.t2 < q, "INVALID_INPUT");
        require(i.t3 < q, "INVALID_INPUT");
        require(i.t4 < q, "INVALID_INPUT");
        require(i.t5 < q, "INVALID_INPUT");
        require(i.t6 < q, "INVALID_INPUT");

        // round 0
        ark(i, q, 14397397413755236225575615486459253198602422701513067526754101844196324375522);
        sbox_full(i, q);
        mix(i, q);
        // round 1
        ark(i, q, 10405129301473404666785234951972711717481302463898292859783056520670200613128);
        sbox_full(i, q);
        mix(i, q);
        // round 2
        ark(i, q, 5179144822360023508491245509308555580251733042407187134628755730783052214509);
        sbox_full(i, q);
        mix(i, q);
        // round 3
        ark(i, q, 9132640374240188374542843306219594180154739721841249568925550236430986592615);
        sbox_partial(i, q);
        mix(i, q);
        // round 4
        ark(i, q, 20360807315276763881209958738450444293273549928693737723235350358403012458514);
        sbox_partial(i, q);
        mix(i, q);
        // round 5
        ark(i, q, 17933600965499023212689924809448543050840131883187652471064418452962948061619);
        sbox_partial(i, q);
        mix(i, q);
        // round 6
        ark(i, q, 3636213416533737411392076250708419981662897009810345015164671602334517041153);
        sbox_partial(i, q);
        mix(i, q);
        // round 7
        ark(i, q, 2008540005368330234524962342006691994500273283000229509835662097352946198608);
        sbox_partial(i, q);
        mix(i, q);
        // round 8
        ark(i, q, 16018407964853379535338740313053768402596521780991140819786560130595652651567);
        sbox_partial(i, q);
        mix(i, q);
        // round 9
        ark(i, q, 20653139667070586705378398435856186172195806027708437373983929336015162186471);
        sbox_partial(i, q);
        mix(i, q);
        // round 10
        ark(i, q, 17887713874711369695406927657694993484804203950786446055999405564652412116765);
        sbox_partial(i, q);
        mix(i, q);
        // round 11
        ark(i, q, 4852706232225925756777361208698488277369799648067343227630786518486608711772);
        sbox_partial(i, q);
        mix(i, q);
        // round 12
        ark(i, q, 8969172011633935669771678412400911310465619639756845342775631896478908389850);
        sbox_partial(i, q);
        mix(i, q);
        // round 13
        ark(i, q, 20570199545627577691240476121888846460936245025392381957866134167601058684375);
        sbox_partial(i, q);
        mix(i, q);
        // round 14
        ark(i, q, 16442329894745639881165035015179028112772410105963688121820543219662832524136);
        sbox_partial(i, q);
        mix(i, q);
        // round 15
        ark(i, q, 20060625627350485876280451423010593928172611031611836167979515653463693899374);
        sbox_partial(i, q);
        mix(i, q);
        // round 16
        ark(i, q, 16637282689940520290130302519163090147511023430395200895953984829546679599107);
        sbox_partial(i, q);
        mix(i, q);
        // round 17
        ark(i, q, 15599196921909732993082127725908821049411366914683565306060493533569088698214);
        sbox_partial(i, q);
        mix(i, q);
        // round 18
        ark(i, q, 16894591341213863947423904025624185991098788054337051624251730868231322135455);
        sbox_partial(i, q);
        mix(i, q);
        // round 19
        ark(i, q, 1197934381747032348421303489683932612752526046745577259575778515005162320212);
        sbox_partial(i, q);
        mix(i, q);
        // round 20
        ark(i, q, 6172482022646932735745595886795230725225293469762393889050804649558459236626);
        sbox_partial(i, q);
        mix(i, q);
        // round 21
        ark(i, q, 21004037394166516054140386756510609698837211370585899203851827276330669555417);
        sbox_partial(i, q);
        mix(i, q);
        // round 22
        ark(i, q, 15262034989144652068456967541137853724140836132717012646544737680069032573006);
        sbox_partial(i, q);
        mix(i, q);
        // round 23
        ark(i, q, 15017690682054366744270630371095785995296470601172793770224691982518041139766);
        sbox_partial(i, q);
        mix(i, q);
        // round 24
        ark(i, q, 15159744167842240513848638419303545693472533086570469712794583342699782519832);
        sbox_partial(i, q);
        mix(i, q);
        // round 25
        ark(i, q, 11178069035565459212220861899558526502477231302924961773582350246646450941231);
        sbox_partial(i, q);
        mix(i, q);
        // round 26
        ark(i, q, 21154888769130549957415912997229564077486639529994598560737238811887296922114);
        sbox_partial(i, q);
        mix(i, q);
        // round 27
        ark(i, q, 20162517328110570500010831422938033120419484532231241180224283481905744633719);
        sbox_partial(i, q);
        mix(i, q);
        // round 28
        ark(i, q, 2777362604871784250419758188173029886707024739806641263170345377816177052018);
        sbox_partial(i, q);
        mix(i, q);
        // round 29
        ark(i, q, 15732290486829619144634131656503993123618032247178179298922551820261215487562);
        sbox_partial(i, q);
        mix(i, q);
        // round 30
        ark(i, q, 6024433414579583476444635447152826813568595303270846875177844482142230009826);
        sbox_partial(i, q);
        mix(i, q);
        // round 31
        ark(i, q, 17677827682004946431939402157761289497221048154630238117709539216286149983245);
        sbox_partial(i, q);
        mix(i, q);
        // round 32
        ark(i, q, 10716307389353583413755237303156291454109852751296156900963208377067748518748);
        sbox_partial(i, q);
        mix(i, q);
        // round 33
        ark(i, q, 14925386988604173087143546225719076187055229908444910452781922028996524347508);
        sbox_partial(i, q);
        mix(i, q);
        // round 34
        ark(i, q, 8940878636401797005293482068100797531020505636124892198091491586778667442523);
        sbox_partial(i, q);
        mix(i, q);
        // round 35
        ark(i, q, 18911747154199663060505302806894425160044925686870165583944475880789706164410);
        sbox_partial(i, q);
        mix(i, q);
        // round 36
        ark(i, q, 8821532432394939099312235292271438180996556457308429936910969094255825456935);
        sbox_partial(i, q);
        mix(i, q);
        // round 37
        ark(i, q, 20632576502437623790366878538516326728436616723089049415538037018093616927643);
        sbox_partial(i, q);
        mix(i, q);
        // round 38
        ark(i, q, 71447649211767888770311304010816315780740050029903404046389165015534756512);
        sbox_partial(i, q);
        mix(i, q);
        // round 39
        ark(i, q, 2781996465394730190470582631099299305677291329609718650018200531245670229393);
        sbox_partial(i, q);
        mix(i, q);
        // round 40
        ark(i, q, 12441376330954323535872906380510501637773629931719508864016287320488688345525);
        sbox_partial(i, q);
        mix(i, q);
        // round 41
        ark(i, q, 2558302139544901035700544058046419714227464650146159803703499681139469546006);
        sbox_partial(i, q);
        mix(i, q);
        // round 42
        ark(i, q, 10087036781939179132584550273563255199577525914374285705149349445480649057058);
        sbox_partial(i, q);
        mix(i, q);
        // round 43
        ark(i, q, 4267692623754666261749551533667592242661271409704769363166965280715887854739);
        sbox_partial(i, q);
        mix(i, q);
        // round 44
        ark(i, q, 4945579503584457514844595640661884835097077318604083061152997449742124905548);
        sbox_partial(i, q);
        mix(i, q);
        // round 45
        ark(i, q, 17742335354489274412669987990603079185096280484072783973732137326144230832311);
        sbox_partial(i, q);
        mix(i, q);
        // round 46
        ark(i, q, 6266270088302506215402996795500854910256503071464802875821837403486057988208);
        sbox_partial(i, q);
        mix(i, q);
        // round 47
        ark(i, q, 2716062168542520412498610856550519519760063668165561277991771577403400784706);
        sbox_partial(i, q);
        mix(i, q);
        // round 48
        ark(i, q, 19118392018538203167410421493487769944462015419023083813301166096764262134232);
        sbox_partial(i, q);
        mix(i, q);
        // round 49
        ark(i, q, 9386595745626044000666050847309903206827901310677406022353307960932745699524);
        sbox_partial(i, q);
        mix(i, q);
        // round 50
        ark(i, q, 9121640807890366356465620448383131419933298563527245687958865317869840082266);
        sbox_partial(i, q);
        mix(i, q);
        // round 51
        ark(i, q, 3078975275808111706229899605611544294904276390490742680006005661017864583210);
        sbox_partial(i, q);
        mix(i, q);
        // round 52
        ark(i, q, 7157404299437167354719786626667769956233708887934477609633504801472827442743);
        sbox_partial(i, q);
        mix(i, q);
        // round 53
        ark(i, q, 14056248655941725362944552761799461694550787028230120190862133165195793034373);
        sbox_partial(i, q);
        mix(i, q);
        // round 54
        ark(i, q, 14124396743304355958915937804966111851843703158171757752158388556919187839849);
        sbox_partial(i, q);
        mix(i, q);
        // round 55
        ark(i, q, 11851254356749068692552943732920045260402277343008629727465773766468466181076);
        sbox_full(i, q);
        mix(i, q);
        // round 56
        ark(i, q, 9799099446406796696742256539758943483211846559715874347178722060519817626047);
        sbox_full(i, q);
        mix(i, q);
        // round 57
        ark(i, q, 10156146186214948683880719664738535455146137901666656566575307300522957959544);
        sbox_full(i, q);
        mix(i, q);

        return i.t0;
    }

}

// File: contracts/lib/ERC20SafeTransfer.sol

// Copyright 2017 Loopring Technology Limited.


/// @title ERC20 safe transfer
/// @dev see https://github.com/sec-bit/badERC20Fix
/// @author Brecht Devos - <[email protected]>
library ERC20SafeTransfer
{
    function safeTransferAndVerify(
        address token,
        address to,
        uint    value
        )
        internal
    {
        safeTransferWithGasLimitAndVerify(
            token,
            to,
            value,
            gasleft()
        );
    }

    function safeTransfer(
        address token,
        address to,
        uint    value
        )
        internal
        returns (bool)
    {
        return safeTransferWithGasLimit(
            token,
            to,
            value,
            gasleft()
        );
    }

    function safeTransferWithGasLimitAndVerify(
        address token,
        address to,
        uint    value,
        uint    gasLimit
        )
        internal
    {
        require(
            safeTransferWithGasLimit(token, to, value, gasLimit),
            "TRANSFER_FAILURE"
        );
    }

    function safeTransferWithGasLimit(
        address token,
        address to,
        uint    value,
        uint    gasLimit
        )
        internal
        returns (bool)
    {
        // A transfer is successful when 'call' is successful and depending on the token:
        // - No value is returned: we assume a revert when the transfer failed (i.e. 'call' returns false)
        // - A single boolean is returned: this boolean needs to be true (non-zero)

        // bytes4(keccak256("transfer(address,uint256)")) = 0xa9059cbb
        bytes memory callData = abi.encodeWithSelector(
            bytes4(0xa9059cbb),
            to,
            value
        );
        (bool success, ) = token.call{gas: gasLimit}(callData);
        return checkReturnValue(success);
    }

    function safeTransferFromAndVerify(
        address token,
        address from,
        address to,
        uint    value
        )
        internal
    {
        safeTransferFromWithGasLimitAndVerify(
            token,
            from,
            to,
            value,
            gasleft()
        );
    }

    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint    value
        )
        internal
        returns (bool)
    {
        return safeTransferFromWithGasLimit(
            token,
            from,
            to,
            value,
            gasleft()
        );
    }

    function safeTransferFromWithGasLimitAndVerify(
        address token,
        address from,
        address to,
        uint    value,
        uint    gasLimit
        )
        internal
    {
        bool result = safeTransferFromWithGasLimit(
            token,
            from,
            to,
            value,
            gasLimit
        );
        require(result, "TRANSFER_FAILURE");
    }

    function safeTransferFromWithGasLimit(
        address token,
        address from,
        address to,
        uint    value,
        uint    gasLimit
        )
        internal
        returns (bool)
    {
        // A transferFrom is successful when 'call' is successful and depending on the token:
        // - No value is returned: we assume a revert when the transfer failed (i.e. 'call' returns false)
        // - A single boolean is returned: this boolean needs to be true (non-zero)

        // bytes4(keccak256("transferFrom(address,address,uint256)")) = 0x23b872dd
        bytes memory callData = abi.encodeWithSelector(
            bytes4(0x23b872dd),
            from,
            to,
            value
        );
        (bool success, ) = token.call{gas: gasLimit}(callData);
        return checkReturnValue(success);
    }

    function checkReturnValue(
        bool success
        )
        internal
        pure
        returns (bool)
    {
        // A transfer/transferFrom is successful when 'call' is successful and depending on the token:
        // - No value is returned: we assume a revert when the transfer failed (i.e. 'call' returns false)
        // - A single boolean is returned: this boolean needs to be true (non-zero)
        if (success) {
            assembly {
                switch returndatasize()
                // Non-standard ERC20: nothing is returned so if 'call' was successful we assume the transfer succeeded
                case 0 {
                    success := 1
                }
                // Standard ERC20: a single boolean value is returned which needs to be true
                case 32 {
                    returndatacopy(0, 0, 32)
                    success := mload(0)
                }
                // None of the above: not successful
                default {
                    success := 0
                }
            }
        }
        return success;
    }
}

// File: contracts/core/impl/libexchange/ExchangeMode.sol

// Copyright 2017 Loopring Technology Limited.




/// @title ExchangeMode.
/// @dev All methods in this lib are internal, therefore, there is no need
///      to deploy this library independently.
/// @author Brecht Devos - <[email protected]>
/// @author Daniel Wang  - <[email protected]>
library ExchangeMode
{
    using MathUint  for uint;

    function isInWithdrawalMode(
        ExchangeData.State storage S
        )
        internal // inline call
        view
        returns (bool result)
    {
        result = S.withdrawalModeStartTime > 0;
    }

    function isShutdown(
        ExchangeData.State storage S
        )
        internal // inline call
        view
        returns (bool)
    {
        return S.shutdownModeStartTime > 0;
    }

    function getNumAvailableForcedSlots(
        ExchangeData.State storage S
        )
        internal
        view
        returns (uint)
    {
        return ExchangeData.MAX_OPEN_FORCED_REQUESTS - S.numPendingForcedTransactions;
    }
}

// File: contracts/core/impl/libexchange/ExchangeTokens.sol

// Copyright 2017 Loopring Technology Limited.






/// @title ExchangeTokens.
/// @author Daniel Wang  - <[email protected]>
/// @author Brecht Devos - <[email protected]>
library ExchangeTokens
{
    using MathUint          for uint;
    using ERC20SafeTransfer for address;
    using ExchangeMode      for ExchangeData.State;

    event TokenRegistered(
        address token,
        uint16  tokenId
    );

    function getTokenAddress(
        ExchangeData.State storage S,
        uint16 tokenID
        )
        public
        view
        returns (address)
    {
        require(tokenID < S.tokens.length, "INVALID_TOKEN_ID");
        return S.tokens[tokenID].token;
    }

    function registerToken(
        ExchangeData.State storage S,
        address tokenAddress
        )
        public
        returns (uint16 tokenID)
    {
        require(!S.isInWithdrawalMode(), "INVALID_MODE");
        require(S.tokenToTokenId[tokenAddress] == 0, "TOKEN_ALREADY_EXIST");
        require(S.tokens.length < ExchangeData.NFT_TOKEN_ID_START, "TOKEN_REGISTRY_FULL");

        // Check if the deposit contract supports the new token
        if (S.depositContract != IDepositContract(0)) {
            require(
                S.depositContract.isTokenSupported(tokenAddress),
                "UNSUPPORTED_TOKEN"
            );
        }

        // Assign a tokenID and store the token
        ExchangeData.Token memory token = ExchangeData.Token(
            tokenAddress
        );
        tokenID = uint16(S.tokens.length);
        S.tokens.push(token);
        S.tokenToTokenId[tokenAddress] = tokenID + 1;

        emit TokenRegistered(tokenAddress, tokenID);
    }

    function getTokenID(
        ExchangeData.State storage S,
        address tokenAddress
        )
        internal  // inline call
        view
        returns (uint16 tokenID)
    {
        tokenID = S.tokenToTokenId[tokenAddress];
        require(tokenID != 0, "TOKEN_NOT_FOUND");
        tokenID = tokenID - 1;
    }

    function isNFT(uint16 tokenID)
        internal  // inline call
        pure
        returns (bool)
    {
        return tokenID >= ExchangeData.NFT_TOKEN_ID_START;
    }
}

// File: contracts/core/impl/libexchange/ExchangeBalances.sol

// Copyright 2017 Loopring Technology Limited.






/// @title ExchangeBalances.
/// @author Daniel Wang  - <[email protected]>
/// @author Brecht Devos - <[email protected]>
library ExchangeBalances
{
    using ExchangeTokens  for uint16;
    using MathUint        for uint;

    function verifyAccountBalance(
        uint                              merkleRoot,
        ExchangeData.MerkleProof calldata merkleProof
        )
        public
        pure
    {
        require(
            isAccountBalanceCorrect(merkleRoot, merkleProof),
            "INVALID_MERKLE_TREE_DATA"
        );
    }

    function isAccountBalanceCorrect(
        uint                            merkleRoot,
        ExchangeData.MerkleProof memory merkleProof
        )
        public
        pure
        returns (bool)
    {
        // Calculate the Merkle root using the Merkle paths provided
        uint calculatedRoot = getBalancesRoot(
            merkleProof.balanceLeaf.tokenID,
            merkleProof.balanceLeaf.balance,
            merkleProof.balanceLeaf.weightAMM,
            merkleProof.balanceLeaf.storageRoot,
            merkleProof.balanceMerkleProof
        );
        calculatedRoot = getAccountInternalsRoot(
            merkleProof.accountLeaf.accountID,
            merkleProof.accountLeaf.owner,
            merkleProof.accountLeaf.pubKeyX,
            merkleProof.accountLeaf.pubKeyY,
            merkleProof.accountLeaf.nonce,
            merkleProof.accountLeaf.feeBipsAMM,
            calculatedRoot,
            merkleProof.accountMerkleProof
        );

        if (merkleProof.balanceLeaf.tokenID.isNFT()) {
            // Verify the NFT data
            uint minter = uint(merkleProof.nft.minter);
            uint nftType = uint(merkleProof.nft.nftType);
            uint token = uint(merkleProof.nft.token);
            uint nftIDLo = merkleProof.nft.nftID & 0xffffffffffffffffffffffffffffffff;
            uint nftIDHi = merkleProof.nft.nftID >> 128;
            uint creatorFeeBips = merkleProof.nft.creatorFeeBips;
            Poseidon.HashInputs7 memory inputs = Poseidon.HashInputs7(
                minter,
                nftType,
                token,
                nftIDLo,
                nftIDHi,
                creatorFeeBips,
                0
            );
            uint nftData = Poseidon.hash_t7f6p52(inputs, ExchangeData.SNARK_SCALAR_FIELD);
            if (nftData != merkleProof.balanceLeaf.weightAMM) {
                return false;
            }
        }

        // Check against the expected Merkle root
        return (calculatedRoot == merkleRoot);
    }

    function getBalancesRoot(
        uint16   tokenID,
        uint     balance,
        uint     weightAMM,
        uint     storageRoot,
        uint[24] memory balanceMerkleProof
        )
        private
        pure
        returns (uint)
    {
        // Hash the balance leaf
        uint balanceItem = hashImpl(balance, weightAMM, storageRoot, 0);
        // Calculate the Merkle root of the balance quad Merkle tree
        uint _id = tokenID;
        for (uint depth = 0; depth < 8; depth++) {
            uint base = depth * 3;
            if (_id & 3 == 0) {
                balanceItem = hashImpl(
                    balanceItem,
                    balanceMerkleProof[base],
                    balanceMerkleProof[base + 1],
                    balanceMerkleProof[base + 2]
                );
            } else if (_id & 3 == 1) {
                balanceItem = hashImpl(
                    balanceMerkleProof[base],
                    balanceItem,
                    balanceMerkleProof[base + 1],
                    balanceMerkleProof[base + 2]
                );
            } else if (_id & 3 == 2) {
                balanceItem = hashImpl(
                    balanceMerkleProof[base],
                    balanceMerkleProof[base + 1],
                    balanceItem,
                    balanceMerkleProof[base + 2]
                );
            } else if (_id & 3 == 3) {
                balanceItem = hashImpl(
                    balanceMerkleProof[base],
                    balanceMerkleProof[base + 1],
                    balanceMerkleProof[base + 2],
                    balanceItem
                );
            }
            _id = _id >> 2;
        }
        return balanceItem;
    }

    function getAccountInternalsRoot(
        uint32   accountID,
        address  owner,
        uint     pubKeyX,
        uint     pubKeyY,
        uint     nonce,
        uint     feeBipsAMM,
        uint     balancesRoot,
        uint[48] memory accountMerkleProof
        )
        private
        pure
        returns (uint)
    {
        // Hash the account leaf
        uint accountItem = hashAccountLeaf(uint(owner), pubKeyX, pubKeyY, nonce, feeBipsAMM, balancesRoot);
        // Calculate the Merkle root of the account quad Merkle tree
        uint _id = accountID;
        for (uint depth = 0; depth < 16; depth++) {
            uint base = depth * 3;
            if (_id & 3 == 0) {
                accountItem = hashImpl(
                    accountItem,
                    accountMerkleProof[base],
                    accountMerkleProof[base + 1],
                    accountMerkleProof[base + 2]
                );
            } else if (_id & 3 == 1) {
                accountItem = hashImpl(
                    accountMerkleProof[base],
                    accountItem,
                    accountMerkleProof[base + 1],
                    accountMerkleProof[base + 2]
                );
            } else if (_id & 3 == 2) {
                accountItem = hashImpl(
                    accountMerkleProof[base],
                    accountMerkleProof[base + 1],
                    accountItem,
                    accountMerkleProof[base + 2]
                );
            } else if (_id & 3 == 3) {
                accountItem = hashImpl(
                    accountMerkleProof[base],
                    accountMerkleProof[base + 1],
                    accountMerkleProof[base + 2],
                    accountItem
                );
            }
            _id = _id >> 2;
        }
        return accountItem;
    }

    function hashAccountLeaf(
        uint t0,
        uint t1,
        uint t2,
        uint t3,
        uint t4,
        uint t5
        )
        public
        pure
        returns (uint)
    {
        Poseidon.HashInputs7 memory inputs = Poseidon.HashInputs7(t0, t1, t2, t3, t4, t5, 0);
        return Poseidon.hash_t7f6p52(inputs, ExchangeData.SNARK_SCALAR_FIELD);
    }

    function hashImpl(
        uint t0,
        uint t1,
        uint t2,
        uint t3
        )
        private
        pure
        returns (uint)
    {
        Poseidon.HashInputs5 memory inputs = Poseidon.HashInputs5(t0, t1, t2, t3, 0);
        return Poseidon.hash_t5f6p52(inputs, ExchangeData.SNARK_SCALAR_FIELD);
    }
}

// File: contracts/core/iface/IL2MintableNFT.sol

// Copyright 2017 Loopring Technology Limited.


interface IL2MintableNFT
{
    /// @dev This function is called when an NFT minted on L2 is withdrawn from Loopring.
    ///      That means the NFTs were burned on L2 and now need to be minted on L1.
    ///
    ///      This function can only be called by the Loopring exchange.
    ///
    /// @param to The owner of the NFT
    /// @param tokenId The token type 'id`
    /// @param amount The amount of NFTs to mint
    /// @param minter The minter on L2, which can be used to decide if the NFT is authentic
    /// @param data Opaque data that can be used by the contract
    function mintFromL2(
        address          to,
        uint256          tokenId,
        uint             amount,
        address          minter,
        bytes   calldata data
        )
        external;

    /// @dev Returns a list of all address that are authorized to mint NFTs on L2.
    /// @return The list of authorized minter on L2
    function minters()
        external
        view
        returns (address[] memory);
}

// File: contracts/thirdparty/erc165/IERC165.sol



/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// File: contracts/thirdparty/erc165/ERC165.sol




/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 */
abstract contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    /**
     * @dev Mapping of interface ids to whether or not it's supported.
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    constructor () {
        // Derived contracts need only register support for their own interfaces,
        // we register support for ERC165 itself here
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     *
     * Time complexity O(1), guaranteed to always use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See {IERC165-supportsInterface}.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal virtual {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}

// File: contracts/thirdparty/erc1155/IERC1155.sol




/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
}

// File: contracts/thirdparty/erc721/IERC721.sol




/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
      * @dev Safely transfers `tokenId` token from `from` to `to`.
      *
      * Requirements:
      *
      * - `from` cannot be the zero address.
      * - `to` cannot be the zero address.
      * - `tokenId` token must exist and be owned by `from`.
      * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
      * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
      *
      * Emits a {Transfer} event.
      */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}

// File: contracts/core/impl/libexchange/ExchangeNFT.sol

// Copyright 2017 Loopring Technology Limited.






/// @title ExchangeNFT
/// @author Brecht Devos - <[email protected]>
library ExchangeNFT
{
    using ExchangeNFT for ExchangeData.State;

    function deposit(
        ExchangeData.State storage S,
        address                    from,
        ExchangeData.NftType       nftType,
        address                    token,
        uint256                    nftID,
        uint                       amount,
        bytes              memory  extraData
        )
        internal
    {
        if (amount == 0) {
            return;
        }

        // Disable calls to certain contracts
        require(S.isTokenAddressAllowed(token), "TOKEN_ADDRESS_NOT_ALLOWED");

        if (nftType == ExchangeData.NftType.ERC1155) {
            IERC1155(token).safeTransferFrom(
                from,
                address(this),
                nftID,
                amount,
                extraData
            );
        } else if (nftType == ExchangeData.NftType.ERC721) {
            require(amount == 1, "INVALID_AMOUNT");
            IERC721(token).safeTransferFrom(
                from,
                address(this),
                nftID,
                extraData
            );
        } else {
            revert("UNKNOWN_NFTTYPE");
        }
    }

    function withdraw(
        ExchangeData.State storage S,
        address              /*from*/,
        address              to,
        ExchangeData.NftType nftType,
        address              token,
        uint256              nftID,
        uint                 amount,
        bytes   memory       extraData,
        uint                 gasLimit
        )
        internal
        returns (bool success)
    {
        if (amount == 0) {
            return true;
        }

        // Disable calls to certain contracts
        if(!S.isTokenAddressAllowed(token)) {
            return false;
        }

        if (nftType == ExchangeData.NftType.ERC1155) {
            try IERC1155(token).safeTransferFrom{gas: gasLimit}(
                address(this),
                to,
                nftID,
                amount,
                extraData
            ) {
                success = true;
            } catch {
                success = false;
            }
        } else if (nftType == ExchangeData.NftType.ERC721) {
            try IERC721(token).safeTransferFrom{gas: gasLimit}(
                address(this),
                to,
                nftID,
                extraData
            ) {
                success = true;
            } catch {
                success = false;
            }
        } else {
            revert("UNKNOWN_NFTTYPE");
        }
    }

    function mintFromL2(
        ExchangeData.State storage S,
        address                    to,
        address                    token,
        uint256                    nftID,
        uint                       amount,
        address                    minter,
        bytes              memory  extraData,
        uint                       gasLimit
        )
        internal
        returns (bool success)
    {
        if (amount == 0) {
            return true;
        }

        // Disable calls to certain contracts
        if(!S.isTokenAddressAllowed(token)) {
            return false;
        }

        try IL2MintableNFT(token).mintFromL2{gas: gasLimit}(
            to,
            nftID,
            amount,
            minter,
            extraData
        ) {
            success = true;
        } catch {
            success = false;
        }
    }

    function isTokenAddressAllowed(
        ExchangeData.State storage S,
        address                    token
        )
        internal
        view
        returns (bool valid)
    {
        return (token != address(this) && token != address(S.depositContract));
    }
}

// File: contracts/core/impl/libexchange/ExchangeWithdrawals.sol

// Copyright 2017 Loopring Technology Limited.









/// @title ExchangeWithdrawals.
/// @author Brecht Devos - <[email protected]>
/// @author Daniel Wang  - <[email protected]>
library ExchangeWithdrawals
{
    enum WithdrawalCategory
    {
        DISTRIBUTION,
        FROM_MERKLE_TREE,
        FROM_DEPOSIT_REQUEST,
        FROM_APPROVED_WITHDRAWAL
    }

    using AddressUtil       for address;
    using AddressUtil       for address payable;
    using BytesUtil         for bytes;
    using MathUint          for uint;
    using ExchangeBalances  for ExchangeData.State;
    using ExchangeMode      for ExchangeData.State;
    using ExchangeTokens    for ExchangeData.State;
    using ExchangeTokens    for uint16;

    event ForcedWithdrawalRequested(
        address owner,
        uint16  tokenID,    // ERC20 token ID ( if < NFT_TOKEN_ID_START) or
                            // NFT balance slot (if >= NFT_TOKEN_ID_START)
        uint32  accountID
    );

    event WithdrawalCompleted(
        uint8   category,
        address from,
        address to,
        address token,
        uint    amount
    );

    event WithdrawalFailed(
        uint8   category,
        address from,
        address to,
        address token,
        uint    amount
    );

    event NftWithdrawalCompleted(
        uint8   category,
        address from,
        address to,
        uint16  tokenID,
        address token,
        uint256 nftID,
        uint    amount
    );

    event NftWithdrawalFailed(
        uint8   category,
        address from,
        address to,
        uint16  tokenID,
        address token,
        uint256 nftID,
        uint    amount
    );

    function forceWithdraw(
        ExchangeData.State storage S,
        address                    owner,
        uint16                     tokenID, // ERC20 token ID ( if < NFT_TOKEN_ID_START) or
                                            // NFT balance slot (if >= NFT_TOKEN_ID_START)
        uint32                     accountID
        )
        public
    {
        require(!S.isInWithdrawalMode(), "INVALID_MODE");
        // Limit the amount of pending forced withdrawals so that the owner cannot be overwhelmed.
        require(S.getNumAvailableForcedSlots() > 0, "TOO_MANY_REQUESTS_OPEN");
        require(accountID < ExchangeData.MAX_NUM_ACCOUNTS, "INVALID_ACCOUNTID");
        // Only allow withdrawing from registered ERC20 tokens or NFT tokenIDs
        require(
            tokenID < S.tokens.length ||                 // ERC20
            tokenID.isNFT(),  // NFT
            "INVALID_TOKENID"
        );

        // A user needs to pay a fixed ETH withdrawal fee, set by the protocol.
        uint withdrawalFeeETH = S.loopring.forcedWithdrawalFee();

        // Check ETH value sent, can be larger than the expected withdraw fee
        require(msg.value >= withdrawalFeeETH, "INSUFFICIENT_FEE");

        // Send surplus of ETH back to the sender
        uint feeSurplus = msg.value.sub(withdrawalFeeETH);
        if (feeSurplus > 0) {
            msg.sender.sendETHAndVerify(feeSurplus, gasleft());
        }

        // There can only be a single forced withdrawal per (account, token) pair.
        require(
            S.pendingForcedWithdrawals[accountID][tokenID].timestamp == 0,
            "WITHDRAWAL_ALREADY_PENDING"
        );

        // Store the forced withdrawal request data
        S.pendingForcedWithdrawals[accountID][tokenID] = ExchangeData.ForcedWithdrawal({
            owner: owner,
            timestamp: uint64(block.timestamp)
        });

        // Increment the number of pending forced transactions so we can keep count.
        S.numPendingForcedTransactions++;

        emit ForcedWithdrawalRequested(
            owner,
            tokenID,
            accountID
        );
    }

    // We alow anyone to withdraw these funds for the account owner
    function withdrawFromMerkleTree(
        ExchangeData.State       storage  S,
        ExchangeData.MerkleProof calldata merkleProof
        )
        public
    {
        require(S.isInWithdrawalMode(), "NOT_IN_WITHDRAW_MODE");

        address owner = merkleProof.accountLeaf.owner;
        uint32 accountID = merkleProof.accountLeaf.accountID;
        uint16 tokenID = merkleProof.balanceLeaf.tokenID;
        uint96 balance = merkleProof.balanceLeaf.balance;

        // Make sure the funds aren't withdrawn already.
        require(S.withdrawnInWithdrawMode[accountID][tokenID] == false, "WITHDRAWN_ALREADY");

        // Verify that the provided Merkle tree data is valid by using the Merkle proof.
        ExchangeBalances.verifyAccountBalance(
            uint(S.merkleRoot),
            merkleProof
        );

        // Make sure the balance can only be withdrawn once
        S.withdrawnInWithdrawMode[accountID][tokenID] = true;

        if (!tokenID.isNFT()) {
            require(
                merkleProof.nft.nftID == 0 && merkleProof.nft.minter == address(0),
                "NOT_AN_NFT"
            );
            // Transfer the tokens to the account owner
            transferTokens(
                S,
                uint8(WithdrawalCategory.FROM_MERKLE_TREE),
                owner,
                owner,
                tokenID,
                balance,
                new bytes(0),
                gasleft(),
                false
            );
        } else {
            transferNFTs(
                S,
                uint8(WithdrawalCategory.DISTRIBUTION),
                owner,
                owner,
                tokenID,
                balance,
                merkleProof.nft,
                new bytes(0),
                gasleft(),
                false
            );
        }
    }

    function withdrawFromDepositRequest(
        ExchangeData.State storage S,
        address                    owner,
        address                    token
        )
        public
    {
        uint16 tokenID = S.getTokenID(token);
        ExchangeData.Deposit storage deposit = S.pendingDeposits[owner][tokenID];
        require(deposit.timestamp != 0, "DEPOSIT_NOT_WITHDRAWABLE_YET");

        // Check if the deposit has indeed exceeded the time limit of if the exchange is in withdrawal mode
        require(
            block.timestamp >= deposit.timestamp + S.maxAgeDepositUntilWithdrawable ||
            S.isInWithdrawalMode(),
            "DEPOSIT_NOT_WITHDRAWABLE_YET"
        );

        uint amount = deposit.amount;

        // Reset the deposit request
        delete S.pendingDeposits[owner][tokenID];

        // Transfer the tokens
        transferTokens(
            S,
            uint8(WithdrawalCategory.FROM_DEPOSIT_REQUEST),
            owner,
            owner,
            tokenID,
            amount,
            new bytes(0),
            gasleft(),
            false
        );
    }

    function withdrawFromNFTDepositRequest(
        ExchangeData.State storage S,
        address                    owner,
        address                    token,
        ExchangeData.NftType       nftType,
        uint256                    nftID
        )
        public
    {
        ExchangeData.Deposit storage deposit = S.pendingNFTDeposits[owner][nftType][token][nftID];
        require(deposit.timestamp != 0, "DEPOSIT_NOT_WITHDRAWABLE_YET");

        // Check if the deposit has indeed exceeded the time limit of if the exchange is in withdrawal mode
        require(
            block.timestamp >= deposit.timestamp + S.maxAgeDepositUntilWithdrawable ||
            S.isInWithdrawalMode(),
            "DEPOSIT_NOT_WITHDRAWABLE_YET"
        );

        uint amount = deposit.amount;

        // Reset the deposit request
        delete S.pendingNFTDeposits[owner][nftType][token][nftID];

        ExchangeData.Nft memory nft = ExchangeData.Nft({
            minter: token,
            nftType: nftType,
            token: token,
            nftID: nftID,
            creatorFeeBips: 0
        });

        // Transfer the NFTs
        transferNFTs(
            S,
            uint8(WithdrawalCategory.FROM_DEPOSIT_REQUEST),
            owner,
            owner,
            0,
            amount,
            nft,
            new bytes(0),
            gasleft(),
            false
        );
    }

    function withdrawFromApprovedWithdrawals(
        ExchangeData.State storage S,
        address[]          memory  owners,
        address[]          memory  tokens
        )
        public
    {
        require(owners.length == tokens.length, "INVALID_INPUT_DATA");
        for (uint i = 0; i < owners.length; i++) {
            address owner = owners[i];
            uint16 tokenID = S.getTokenID(tokens[i]);
            uint amount = S.amountWithdrawable[owner][tokenID];

            // Make sure this amount can't be withdrawn again
            delete S.amountWithdrawable[owner][tokenID];

            // Transfer the tokens to the owner
            transferTokens(
                S,
                uint8(WithdrawalCategory.FROM_APPROVED_WITHDRAWAL),
                owner,
                owner,
                tokenID,
                amount,
                new bytes(0),
                gasleft(),
                false
            );
        }
    }

    function withdrawFromApprovedWithdrawalsNFT(
        ExchangeData.State     storage S,
        address[]              memory  owners,
        address[]              memory  minters,
        ExchangeData.NftType[] memory  nftTypes,
        address[]              memory  tokens,
        uint256[]              memory  nftIDs
        )
        public
    {
        require(owners.length == minters.length, "INVALID_INPUT_DATA_MINTERS");
        require(owners.length == nftTypes.length, "INVALID_INPUT_DATA_NFTTYPES");
        require(owners.length == tokens.length, "INVALID_INPUT_DATA_TOKENS");
        require(owners.length == nftIDs.length, "INVALID_INPUT_DATA_CONTENT_URIS");
        for (uint i = 0; i < owners.length; i++) {
            address owner = owners[i];
            address minter = minters[i];
            ExchangeData.NftType nftType = nftTypes[i];
            address token = tokens[i];
            uint256 nftID = nftIDs[i];
            uint amount = S.amountWithdrawableNFT[owner][minter][nftType][token][nftID];

            // Make sure this amount can't be withdrawn again
            delete S.amountWithdrawableNFT[owner][minter][nftType][token][nftID];

            ExchangeData.Nft memory nft = ExchangeData.Nft({
                minter: minter,
                nftType: nftType,
                token: token,
                nftID: nftID,
                creatorFeeBips: 0
            });

            // Transfer the NFTs to the owner
            transferNFTs(
                S,
                uint8(WithdrawalCategory.DISTRIBUTION),
                owner,
                owner,
                0,
                amount,
                nft,
                new bytes(0),
                gasleft(),
                false
            );
        }
    }

    function distributeWithdrawal(
        ExchangeData.State storage S,
        address                    from,
        address                    to,
        uint16                     tokenID,
        uint                       amount,
        bytes              memory  extraData,
        uint                       gasLimit,
        ExchangeData.Nft   memory  nft
        )
        public
    {
        if (!tokenID.isNFT()) {
            // Try to transfer the tokens
            if (!transferTokens(
                S,
                uint8(WithdrawalCategory.DISTRIBUTION),
                from,
                to,
                tokenID,
                amount,
                extraData,
                gasLimit,
                true
            )) {
                // If the transfer was successful there's nothing left to do.
                // However, if the transfer failed the tokens are still in the contract and can be
                // withdrawn later to `to` by anyone by using `withdrawFromApprovedWithdrawal.
                S.amountWithdrawable[to][tokenID] = S.amountWithdrawable[to][tokenID].add(amount);
            }
        } else {
            // Try to transfer the tokens
            if (!transferNFTs(
                S,
                uint8(WithdrawalCategory.DISTRIBUTION),
                from,
                to,
                tokenID,
                amount,
                nft,
                extraData,
                gasLimit,
                true
            )) {
                // If the transfer was successful there's nothing left to do.
                // However, if the transfer failed the tokens are still in the contract and can be
                // withdrawn later to `to` by anyone by using `withdrawFromApprovedNftWithdrawal.
                S.amountWithdrawableNFT[to][nft.minter][nft.nftType][nft.token][nft.nftID] =
                    S.amountWithdrawableNFT[to][nft.minter][nft.nftType][nft.token][nft.nftID].add(amount);
            }
        }
    }

    // == Internal and Private Functions ==

    // If allowFailure is true the transfer can fail because of a transfer error or
    // because the transfer uses more than `gasLimit` gas. The function
    // will return true when successful, false otherwise.
    // If allowFailure is false the transfer is guaranteed to succeed using
    // as much gas as needed, otherwise it throws. The function always returns true.
    function transferTokens(
        ExchangeData.State storage S,
        uint8                      category,
        address                    from,
        address                    to,
        uint16                     tokenID,
        uint                       amount,
        bytes              memory  extraData,
        uint                       gasLimit,
        bool                       allowFailure
        )
        private
        returns (bool success)
    {
        // Redirect withdrawals to address(0) to the protocol fee vault
        if (to == address(0)) {
            to = S.loopring.protocolFeeVault();
        }
        address token = S.getTokenAddress(tokenID);

        // Transfer the tokens from the deposit contract to the owner
        if (gasLimit > 0) {
            try S.depositContract.withdraw{gas: gasLimit}(from, to, token, amount, extraData) {
                success = true;
            } catch {
                success = false;
            }
        } else {
            success = false;
        }

        require(allowFailure || success, "TRANSFER_FAILURE");

        if (success) {
            emit WithdrawalCompleted(category, from, to, token, amount);

            // Keep track of when the protocol fees were last withdrawn
            // (only done to make this data easier available).
            if (from == address(0)) {
                S.protocolFeeLastWithdrawnTime[token] = block.timestamp;
            }
        } else {
            emit WithdrawalFailed(category, from, to, token, amount);
        }
    }

    // If allowFailure is true the transfer can fail because of a transfer error or
    // because the transfer uses more than `gasLimit` gas. The function
    // will return true when successful, false otherwise.
    // If allowFailure is false the transfer is guaranteed to succeed using
    // as much gas as needed, otherwise it throws. The function always returns true.
    function transferNFTs(
        ExchangeData.State storage S,
        uint8                      category,
        address                    from,
        address                    to,
        uint16                     tokenID,
        uint                       amount,
        ExchangeData.Nft   memory  nft,
        bytes              memory  extraData,
        uint                       gasLimit,
        bool                       allowFailure
        )
        private
        returns (bool success)
    {
        if (nft.token == nft.minter) {
            // This is an existing thirdparty NFT contract
            success = ExchangeNFT.withdraw(
                S,
                from,
                to,
                nft.nftType,
                nft.token,
                nft.nftID,
                amount,
                extraData,
                gasLimit
            );
        } else {
            // This is an inhouse NFT contract with L2 minting support
            success = ExchangeNFT.mintFromL2(
                S,
                to,
                nft.token,
                nft.nftID,
                amount,
                nft.minter,
                extraData,
                gasLimit
            );
        }

        require(allowFailure || success, "NFT_TRANSFER_FAILURE");

        if (success) {
            emit NftWithdrawalCompleted(category, from, to, tokenID, nft.token, nft.nftID, amount);
        } else {
            emit NftWithdrawalFailed(category, from, to, tokenID, nft.token, nft.nftID, amount);
        }
    }
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint16","name":"tokenID","type":"uint16"},{"indexed":false,"internalType":"uint32","name":"accountID","type":"uint32"}],"name":"ForcedWithdrawalRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"category","type":"uint8"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint16","name":"tokenID","type":"uint16"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"nftID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NftWithdrawalCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"category","type":"uint8"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint16","name":"tokenID","type":"uint16"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"nftID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NftWithdrawalFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"category","type":"uint8"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawalCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"category","type":"uint8"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawalFailed","type":"event"}]

612c06610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100865760003560e01c8063cae3c78111610065578063cae3c781146100ed578063eaacf5e41461010d578063ef22a02f1461012d578063f460cca91461014d57610086565b8062baadff1461008b57806328da23b6146100ad57806395d75555146100cd575b600080fd5b81801561009757600080fd5b506100ab6100a6366004612081565b61016d565b005b8180156100b957600080fd5b506100ab6100c8366004611f77565b61055b565b8180156100d957600080fd5b506100ab6100e8366004611ede565b61075c565b8180156100f957600080fd5b506100ab61010836600461220d565b610920565b81801561011957600080fd5b506100ab610128366004611f1f565b610bf3565b81801561013957600080fd5b506100ab610148366004612139565b610e54565b81801561015957600080fd5b506100ab6101683660046120cf565b611200565b610176846112ed565b156101b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612733565b60405180910390fd5b60006101c1856112f6565b116101f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612990565b6401000000008163ffffffff161061023c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612922565b600984015461ffff8316108061025a575061025a8261ffff1661130b565b610290576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061287d565b6002840154604080517ffe25eaa8000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163fe25eaa8916004808301926020929190829003018186803b1580156102fd57600080fd5b505afa158015610311573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610335919061227d565b905080341015610371576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906127a1565b600061037d348361131a565b9050801561039457610392815a339190611361565b505b63ffffffff83166000908152600d87016020908152604080832061ffff8816845290915290205474010000000000000000000000000000000000000000900467ffffffffffffffff1615610414576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612959565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff87811682524267ffffffffffffffff908116602080850191825263ffffffff8981166000908152600d8e01835287812061ffff8d168252909252908690209451855492517fffffffffffffffffffffffff00000000000000000000000000000000000000009093169416939093177fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000009190921602179091556011880180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000008116908316600101909216919091179055517f9cdf733df701225f835cfd5df1c6376ef646298f9c2271e86f12078903e260949061054b908790879087906124fe565b60405180910390a1505050505050565b6105688561ffff1661130b565b6106015761057f88600089898989898960016113c4565b6105fc5773ffffffffffffffffffffffffffffffffffffffff86166000908152600c89016020908152604080832061ffff891684529091529020546105c490856116fa565b73ffffffffffffffffffffffffffffffffffffffff87166000908152600c8a016020908152604080832061ffff8a1684529091529020555b610752565b61061588600089898989878a8a6001611737565b6107525773ffffffffffffffffffffffffffffffffffffffff808716600090815260188a016020908152604080832085519094168352928152918120918301516106bc9287929091600181111561066857fe5b600181111561067357fe5b8152602080820192909252604090810160009081208683015173ffffffffffffffffffffffffffffffffffffffff168252835281812060608701518252909252902054906116fa565b73ffffffffffffffffffffffffffffffffffffffff808816600090815260188b01602090815260408083208651909416835292815291812091840151600181111561070357fe5b600181111561070e57fe5b8152602080820192909252604090810160009081208583015173ffffffffffffffffffffffffffffffffffffffff1682528352818120606086015182529092529020555b5050505050505050565b600061076884836118a7565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600e86016020908152604080832061ffff8516845290915290208054919250906c01000000000000000000000000900467ffffffffffffffff166107f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061257b565b8454815467ffffffffffffffff6c01000000000000000000000000909104811663ffffffff9092169190910116421015806108335750610833856112ed565b610869576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061257b565b805473ffffffffffffffffffffffffffffffffffffffff85166000908152600e87016020908152604080832061ffff87168452909152902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556bffffffffffffffffffffffff16610917866002878087866000805b506040519080825280601f01601f19166020018201604052801561090e576020820181803683370190505b505a60006113c4565b50505050505050565b610929826112ed565b61095f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906125b2565b60006109716040830160208401611e8b565b905060006109826020840184612295565b9050600061099660e0850160c08601612263565b905060006109ab610100860160e087016122af565b63ffffffff84166000908152600b88016020908152604080832061ffff8716845290915290205490915060ff1615610a0f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906129c7565b60068601546040517f0c65124d0000000000000000000000000000000000000000000000000000000081527390e222b9bc88072ddf9f0ab668dcc58282f05c3c91630c65124d91610a6591908990600401612a10565b60006040518083038186803b158015610a7d57600080fd5b505af4158015610a91573d6000803e3d6000fd5b50505063ffffffff84166000908152600b88016020908152604080832061ffff8716808552925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610aee915061130b565b610b88576101a0850135158015610b2c57506000610b1461016087016101408801611e8b565b73ffffffffffffffffffffffffffffffffffffffff16145b610b62576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612620565b610b828660018680866bffffffffffffffffffffffff87166000806108e3565b50610beb565b6109178660008680866bffffffffffffffffffffffff8716610bb3368d90038d016101408e01611ec3565b6000805b506040519080825280601f01601f191660200182016040528015610be2576020820181803683370190505b505a6000611737565b505050505050565b73ffffffffffffffffffffffffffffffffffffffff84166000908152601786016020526040812081846001811115610c2757fe5b6001811115610c3257fe5b81526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff881682528352818120858252909252902080549091506c01000000000000000000000000900467ffffffffffffffff16610cc2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061257b565b8554815467ffffffffffffffff6c01000000000000000000000000909104811663ffffffff909216919091011642101580610d015750610d01866112ed565b610d37576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061257b565b805473ffffffffffffffffffffffffffffffffffffffff8616600090815260178801602052604081206bffffffffffffffffffffffff9092169190856001811115610d7e57fe5b6001811115610d8957fe5b81526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff8916808352908452828220878352845282822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055825160a081019093528252918101866001811115610e0657fe5b815273ffffffffffffffffffffffffffffffffffffffff881660208201526040810186905260006060909101529050610e498860025b8980600087878280610bb7565b505050505050505050565b8351855114610e8f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906128b4565b8251855114610eca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061268e565b8151855114610f05576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906127d8565b8051855114610f40576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906125e9565b60005b8551811015610917576000868281518110610f5a57fe5b602002602001015190506000868381518110610f7257fe5b602002602001015190506000868481518110610f8a57fe5b602002602001015190506000868581518110610fa257fe5b602002602001015190506000868681518110610fba57fe5b6020026020010151905060008c60180160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085600181111561105257fe5b600181111561105d57fe5b815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000205490508c60180160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085600181111561114857fe5b600181111561115357fe5b81526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff80881683529084528282208683528452828220829055825160a08101909352881682529181018660018111156111af57fe5b815273ffffffffffffffffffffffffffffffffffffffff8616602082015260408101859052600060609091018190529091506111ec908f90610e3c565b505060019096019550610f43945050505050565b805182511461123b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612657565b60005b82518110156112e757600083828151811061125557fe5b60200260200101519050600061128784848151811061127057fe5b6020026020010151876118a790919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600c88016020908152604080832061ffff85168452909152812080549190559091506112d7876003858086866000806108e3565b50506001909201915061123e9050565b50505050565b60140154151590565b601181015463ffffffff16611000035b919050565b61800061ffff82161015919050565b600082821115611356576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906126fc565b508082035b92915050565b600061138473ffffffffffffffffffffffffffffffffffffffff85168484611932565b9050806113bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906126c5565b9392505050565b600073ffffffffffffffffffffffffffffffffffffffff8716611486578960020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663af1af3b96040518163ffffffff1660e01b815260040160206040518083038186803b15801561144b57600080fd5b505afa15801561145f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114839190611ea7565b96505b6040517ff24789a80000000000000000000000000000000000000000000000000000000081526000907324f51fadc255dfcbc436615167c325cac7010b299063f24789a8906114db908e908b906004016129fe565b60206040518083038186803b1580156114f357600080fd5b505af4158015611507573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152b9190611ea7565b905083156115d85760058b01546040517f3823f24700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690633823f247908690611595908d908d9087908d908d9060040161241e565b600060405180830381600088803b1580156115af57600080fd5b5087f1935050505080156115c1575060015b6115ce57600091506115d3565b600191505b6115dd565b600091505b82806115e65750815b61161c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906126c5565b81156116ac577f0d22d7344fc6871a839149fd89f9fd88a6c29cf797a67114772a9d4df5f8c96b8a8a8a848a604051611659959493929190612ad5565b60405180910390a173ffffffffffffffffffffffffffffffffffffffff89166116a75773ffffffffffffffffffffffffffffffffffffffff8116600090815260158c01602052604090204290555b6116ec565b7fc554475da3c47d29ea41e4f1ba76e92dd5b4b7764dbd96e1fb0d5d1e419bcf8b8a8a8a848a6040516116e3959493929190612ad5565b60405180910390a15b509998505050505050505050565b8181018281101561135b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612846565b6000846000015173ffffffffffffffffffffffffffffffffffffffff16856040015173ffffffffffffffffffffffffffffffffffffffff161415611799576117928b8a8a886020015189604001518a606001518c8b8b6119d9565b90506117b8565b6117b58b89876040015188606001518a8a600001518a8a611b5c565b90505b81806117c15750805b6117f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906128eb565b801561184d577fa1af8cedfbd157f967dd83203fd025ece9cd1ee0f63f38632b24f1e03778bc288a8a8a8a89604001518a606001518c6040516118409796959493929190612b15565b60405180910390a1611899565b7f7cfb0fa39777da32fa26ee2f1cb14cc1c1ecd01e99d1d6bba446143f96db036f8a8a8a8a89604001518a606001518c6040516118909796959493929190612b15565b60405180910390a15b9a9950505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600a8301602052604090205461ffff168061190a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061276a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b600082611941575060016113bd565b60006119628573ffffffffffffffffffffffffffffffffffffffff16611c25565b90508073ffffffffffffffffffffffffffffffffffffffff1684849060405161198a90611c25565b600060405180830381858888f193505050503d80600081146119c8576040519150601f19603f3d011682016040523d82523d6000602084013e6119cd565b606091505b50909695505050505050565b6000836119e857506001611b4f565b6119f28a87611c28565b6119fe57506000611b4f565b6000876001811115611a0c57fe5b1415611aaf576040517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169063f242432a908490611a6e9030908d908b908b908b906004016124b9565b600060405180830381600088803b158015611a8857600080fd5b5087f193505050508015611a9a575060015b611aa657506000611aaa565b5060015b611b4f565b6001876001811115611abd57fe5b1415611b1d576040517fb88d4fde00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169063b88d4fde908490611a6e9030908d908b908a90600401612470565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061280f565b9998505050505050505050565b600084611b6b57506001611c19565b611b758988611c28565b611b8157506000611c19565b6040517f2f680ebe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff881690632f680ebe908490611bdd908c908b908b908b908b90600401612536565b600060405180830381600088803b158015611bf757600080fd5b5087f193505050508015611c09575060015b611c1557506000611c19565b5060015b98975050505050505050565b90565b600073ffffffffffffffffffffffffffffffffffffffff821630148015906113bd5750506005919091015473ffffffffffffffffffffffffffffffffffffffff9081169116141590565b600082601f830112611c82578081fd5b81356020611c97611c9283612b8d565b612b69565b8281528181019085830183850287018401881015611cb3578586fd5b855b85811015611cda578135611cc881612bab565b84529284019290840190600101611cb5565b5090979650505050505050565b600082601f830112611cf7578081fd5b81356020611d07611c9283612b8d565b8281528181019085830183850287018401881015611d23578586fd5b855b85811015611cda57611d3682611da2565b84529284019290840190600101611d25565b600082601f830112611d58578081fd5b81356020611d68611c9283612b8d565b8281528181019085830183850287018401881015611d84578586fd5b855b85811015611cda57813584529284019290840190600101611d86565b80356002811061130657600080fd5b600060a08284031215611dc2578081fd5b60405160a0810181811067ffffffffffffffff82111715611ddf57fe5b6040529050808235611df081612bab565b8152611dfe60208401611da2565b60208201526040830135611e1181612bab565b604082015260608381013590820152611e2c60808401611e5e565b60808201525092915050565b803561ffff8116811461130657600080fd5b803563ffffffff8116811461130657600080fd5b803560ff8116811461130657600080fd5b80356bffffffffffffffffffffffff8116811461130657600080fd5b600060208284031215611e9c578081fd5b81356113bd81612bab565b600060208284031215611eb8578081fd5b81516113bd81612bab565b600060a08284031215611ed4578081fd5b6113bd8383611db1565b600080600060608486031215611ef2578182fd5b833592506020840135611f0481612bab565b91506040840135611f1481612bab565b809150509250925092565b600080600080600060a08688031215611f36578283fd5b853594506020860135611f4881612bab565b93506040860135611f5881612bab565b9250611f6660608701611da2565b949793965091946080013592915050565b600080600080600080600080610180898b031215611f93578586fd5b883597506020808a0135611fa681612bab565b975060408a0135611fb681612bab565b9650611fc460608b01611e38565b955060808a0135945060a08a013567ffffffffffffffff80821115611fe7578586fd5b818c0191508c601f830112611ffa578586fd5b81358181111561200657fe5b612036847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612b69565b91508082528d8482850101111561204b578687fd5b8084840185840137810190920194909452925060c089013591506120728a60e08b01611db1565b90509295985092959890939650565b60008060008060808587031215612096578182fd5b8435935060208501356120a881612bab565b92506120b660408601611e38565b91506120c460608601611e4a565b905092959194509250565b6000806000606084860312156120e3578081fd5b83359250602084013567ffffffffffffffff80821115612101578283fd5b61210d87838801611c72565b93506040860135915080821115612122578283fd5b5061212f86828701611c72565b9150509250925092565b60008060008060008060c08789031215612151578384fd5b86359550602087013567ffffffffffffffff8082111561216f578586fd5b61217b8a838b01611c72565b96506040890135915080821115612190578586fd5b61219c8a838b01611c72565b955060608901359150808211156121b1578384fd5b6121bd8a838b01611ce7565b945060808901359150808211156121d2578384fd5b6121de8a838b01611c72565b935060a08901359150808211156121f3578283fd5b5061220089828a01611d48565b9150509295509295509295565b600080828403610b00811215612221578283fd5b83359250610ae07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082011215612255578182fd5b506020830190509250929050565b600060208284031215612274578081fd5b6113bd82611e38565b60006020828403121561228e578081fd5b5051919050565b6000602082840312156122a6578081fd5b6113bd82611e4a565b6000602082840312156122c0578081fd5b6113bd82611e6f565b61030080828437600081840152505050565b61060080828437600081840152505050565b60008151808452815b81811015612312576020818501810151868301820152016122f6565b818111156123235782602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b61ffff61236282611e38565b1682526bffffffffffffffffffffffff61237e60208301611e6f565b16602083015260408181013590830152606090810135910152565b80356123a481612bab565b73ffffffffffffffffffffffffffffffffffffffff80821684526123ca60208401611da2565b9150600282106123d657fe5b816020850152604083013591506123ec82612bab565b1660408301526060818101359083015260ff61240a60808301611e5e565b1660808301525050565b63ffffffff169052565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525083606083015260a0608083015261246560a08301846122ed565b979650505050505050565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250836040830152608060608301526124af60808301846122ed565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015283606083015260a0608083015261246560a08301846122ed565b73ffffffffffffffffffffffffffffffffffffffff93909316835261ffff91909116602083015263ffffffff16604082015260600190565b600073ffffffffffffffffffffffffffffffffffffffff808816835286602084015285604084015280851660608401525060a0608083015261246560a08301846122ed565b6020808252601c908201527f4445504f5349545f4e4f545f574954484452415741424c455f59455400000000604082015260600190565b60208082526014908201527f4e4f545f494e5f57495448445241575f4d4f4445000000000000000000000000604082015260600190565b6020808252601f908201527f494e56414c49445f494e5055545f444154415f434f4e54454e545f5552495300604082015260600190565b6020808252600a908201527f4e4f545f414e5f4e465400000000000000000000000000000000000000000000604082015260600190565b60208082526012908201527f494e56414c49445f494e5055545f444154410000000000000000000000000000604082015260600190565b6020808252601b908201527f494e56414c49445f494e5055545f444154415f4e465454595045530000000000604082015260600190565b60208082526010908201527f5452414e534645525f4641494c55524500000000000000000000000000000000604082015260600190565b6020808252600d908201527f5355425f554e444552464c4f5700000000000000000000000000000000000000604082015260600190565b6020808252600c908201527f494e56414c49445f4d4f44450000000000000000000000000000000000000000604082015260600190565b6020808252600f908201527f544f4b454e5f4e4f545f464f554e440000000000000000000000000000000000604082015260600190565b60208082526010908201527f494e53554646494349454e545f46454500000000000000000000000000000000604082015260600190565b60208082526019908201527f494e56414c49445f494e5055545f444154415f544f4b454e5300000000000000604082015260600190565b6020808252600f908201527f554e4b4e4f574e5f4e4654545950450000000000000000000000000000000000604082015260600190565b6020808252600c908201527f4144445f4f564552464c4f570000000000000000000000000000000000000000604082015260600190565b6020808252600f908201527f494e56414c49445f544f4b454e49440000000000000000000000000000000000604082015260600190565b6020808252601a908201527f494e56414c49445f494e5055545f444154415f4d494e54455253000000000000604082015260600190565b60208082526014908201527f4e46545f5452414e534645525f4641494c555245000000000000000000000000604082015260600190565b60208082526011908201527f494e56414c49445f4143434f554e544944000000000000000000000000000000604082015260600190565b6020808252601a908201527f5749544844524157414c5f414c52454144595f50454e44494e47000000000000604082015260600190565b60208082526016908201527f544f4f5f4d414e595f52455155455354535f4f50454e00000000000000000000604082015260600190565b60208082526011908201527f57495448445241574e5f414c5245414459000000000000000000000000000000604082015260600190565b91825261ffff16602082015260400190565b828152610b00810163ffffffff612a2684611e4a565b1660208301526020830135612a3a81612bab565b73ffffffffffffffffffffffffffffffffffffffff81166040840152506040830135606083015260608301356080830152612a7760808401611e4a565b612a8460a0840182612414565b5060a083013560c0830152612a9f60e0830160c08501612356565b612ab161016083016101408501612399565b612ac361020083016101e085016122db565b6113bd61080083016107e085016122c9565b60ff95909516855273ffffffffffffffffffffffffffffffffffffffff938416602086015291831660408501529091166060830152608082015260a00190565b60ff97909716875273ffffffffffffffffffffffffffffffffffffffff9586166020880152938516604087015261ffff929092166060860152909216608084015260a083019190915260c082015260e00190565b60405181810167ffffffffffffffff81118282101715612b8557fe5b604052919050565b600067ffffffffffffffff821115612ba157fe5b5060209081020190565b73ffffffffffffffffffffffffffffffffffffffff81168114612bcd57600080fd5b5056fea264697066735822122040306f4eead7414238775f7365298babdf807acb919ca99631cdb02356e7634a64736f6c63430007060033

Deployed Bytecode

0x7346a71e786c34714928390782e9e50ee1c2fa998930146080604052600436106100865760003560e01c8063cae3c78111610065578063cae3c781146100ed578063eaacf5e41461010d578063ef22a02f1461012d578063f460cca91461014d57610086565b8062baadff1461008b57806328da23b6146100ad57806395d75555146100cd575b600080fd5b81801561009757600080fd5b506100ab6100a6366004612081565b61016d565b005b8180156100b957600080fd5b506100ab6100c8366004611f77565b61055b565b8180156100d957600080fd5b506100ab6100e8366004611ede565b61075c565b8180156100f957600080fd5b506100ab61010836600461220d565b610920565b81801561011957600080fd5b506100ab610128366004611f1f565b610bf3565b81801561013957600080fd5b506100ab610148366004612139565b610e54565b81801561015957600080fd5b506100ab6101683660046120cf565b611200565b610176846112ed565b156101b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612733565b60405180910390fd5b60006101c1856112f6565b116101f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612990565b6401000000008163ffffffff161061023c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612922565b600984015461ffff8316108061025a575061025a8261ffff1661130b565b610290576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061287d565b6002840154604080517ffe25eaa8000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163fe25eaa8916004808301926020929190829003018186803b1580156102fd57600080fd5b505afa158015610311573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610335919061227d565b905080341015610371576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906127a1565b600061037d348361131a565b9050801561039457610392815a339190611361565b505b63ffffffff83166000908152600d87016020908152604080832061ffff8816845290915290205474010000000000000000000000000000000000000000900467ffffffffffffffff1615610414576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612959565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff87811682524267ffffffffffffffff908116602080850191825263ffffffff8981166000908152600d8e01835287812061ffff8d168252909252908690209451855492517fffffffffffffffffffffffff00000000000000000000000000000000000000009093169416939093177fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000009190921602179091556011880180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000008116908316600101909216919091179055517f9cdf733df701225f835cfd5df1c6376ef646298f9c2271e86f12078903e260949061054b908790879087906124fe565b60405180910390a1505050505050565b6105688561ffff1661130b565b6106015761057f88600089898989898960016113c4565b6105fc5773ffffffffffffffffffffffffffffffffffffffff86166000908152600c89016020908152604080832061ffff891684529091529020546105c490856116fa565b73ffffffffffffffffffffffffffffffffffffffff87166000908152600c8a016020908152604080832061ffff8a1684529091529020555b610752565b61061588600089898989878a8a6001611737565b6107525773ffffffffffffffffffffffffffffffffffffffff808716600090815260188a016020908152604080832085519094168352928152918120918301516106bc9287929091600181111561066857fe5b600181111561067357fe5b8152602080820192909252604090810160009081208683015173ffffffffffffffffffffffffffffffffffffffff168252835281812060608701518252909252902054906116fa565b73ffffffffffffffffffffffffffffffffffffffff808816600090815260188b01602090815260408083208651909416835292815291812091840151600181111561070357fe5b600181111561070e57fe5b8152602080820192909252604090810160009081208583015173ffffffffffffffffffffffffffffffffffffffff1682528352818120606086015182529092529020555b5050505050505050565b600061076884836118a7565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600e86016020908152604080832061ffff8516845290915290208054919250906c01000000000000000000000000900467ffffffffffffffff166107f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061257b565b8454815467ffffffffffffffff6c01000000000000000000000000909104811663ffffffff9092169190910116421015806108335750610833856112ed565b610869576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061257b565b805473ffffffffffffffffffffffffffffffffffffffff85166000908152600e87016020908152604080832061ffff87168452909152902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556bffffffffffffffffffffffff16610917866002878087866000805b506040519080825280601f01601f19166020018201604052801561090e576020820181803683370190505b505a60006113c4565b50505050505050565b610929826112ed565b61095f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906125b2565b60006109716040830160208401611e8b565b905060006109826020840184612295565b9050600061099660e0850160c08601612263565b905060006109ab610100860160e087016122af565b63ffffffff84166000908152600b88016020908152604080832061ffff8716845290915290205490915060ff1615610a0f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906129c7565b60068601546040517f0c65124d0000000000000000000000000000000000000000000000000000000081527390e222b9bc88072ddf9f0ab668dcc58282f05c3c91630c65124d91610a6591908990600401612a10565b60006040518083038186803b158015610a7d57600080fd5b505af4158015610a91573d6000803e3d6000fd5b50505063ffffffff84166000908152600b88016020908152604080832061ffff8716808552925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610aee915061130b565b610b88576101a0850135158015610b2c57506000610b1461016087016101408801611e8b565b73ffffffffffffffffffffffffffffffffffffffff16145b610b62576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612620565b610b828660018680866bffffffffffffffffffffffff87166000806108e3565b50610beb565b6109178660008680866bffffffffffffffffffffffff8716610bb3368d90038d016101408e01611ec3565b6000805b506040519080825280601f01601f191660200182016040528015610be2576020820181803683370190505b505a6000611737565b505050505050565b73ffffffffffffffffffffffffffffffffffffffff84166000908152601786016020526040812081846001811115610c2757fe5b6001811115610c3257fe5b81526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff881682528352818120858252909252902080549091506c01000000000000000000000000900467ffffffffffffffff16610cc2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061257b565b8554815467ffffffffffffffff6c01000000000000000000000000909104811663ffffffff909216919091011642101580610d015750610d01866112ed565b610d37576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061257b565b805473ffffffffffffffffffffffffffffffffffffffff8616600090815260178801602052604081206bffffffffffffffffffffffff9092169190856001811115610d7e57fe5b6001811115610d8957fe5b81526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff8916808352908452828220878352845282822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055825160a081019093528252918101866001811115610e0657fe5b815273ffffffffffffffffffffffffffffffffffffffff881660208201526040810186905260006060909101529050610e498860025b8980600087878280610bb7565b505050505050505050565b8351855114610e8f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906128b4565b8251855114610eca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061268e565b8151855114610f05576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906127d8565b8051855114610f40576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906125e9565b60005b8551811015610917576000868281518110610f5a57fe5b602002602001015190506000868381518110610f7257fe5b602002602001015190506000868481518110610f8a57fe5b602002602001015190506000868581518110610fa257fe5b602002602001015190506000868681518110610fba57fe5b6020026020010151905060008c60180160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085600181111561105257fe5b600181111561105d57fe5b815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000205490508c60180160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085600181111561114857fe5b600181111561115357fe5b81526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff80881683529084528282208683528452828220829055825160a08101909352881682529181018660018111156111af57fe5b815273ffffffffffffffffffffffffffffffffffffffff8616602082015260408101859052600060609091018190529091506111ec908f90610e3c565b505060019096019550610f43945050505050565b805182511461123b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612657565b60005b82518110156112e757600083828151811061125557fe5b60200260200101519050600061128784848151811061127057fe5b6020026020010151876118a790919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600c88016020908152604080832061ffff85168452909152812080549190559091506112d7876003858086866000806108e3565b50506001909201915061123e9050565b50505050565b60140154151590565b601181015463ffffffff16611000035b919050565b61800061ffff82161015919050565b600082821115611356576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906126fc565b508082035b92915050565b600061138473ffffffffffffffffffffffffffffffffffffffff85168484611932565b9050806113bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906126c5565b9392505050565b600073ffffffffffffffffffffffffffffffffffffffff8716611486578960020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663af1af3b96040518163ffffffff1660e01b815260040160206040518083038186803b15801561144b57600080fd5b505afa15801561145f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114839190611ea7565b96505b6040517ff24789a80000000000000000000000000000000000000000000000000000000081526000907324f51fadc255dfcbc436615167c325cac7010b299063f24789a8906114db908e908b906004016129fe565b60206040518083038186803b1580156114f357600080fd5b505af4158015611507573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152b9190611ea7565b905083156115d85760058b01546040517f3823f24700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690633823f247908690611595908d908d9087908d908d9060040161241e565b600060405180830381600088803b1580156115af57600080fd5b5087f1935050505080156115c1575060015b6115ce57600091506115d3565b600191505b6115dd565b600091505b82806115e65750815b61161c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906126c5565b81156116ac577f0d22d7344fc6871a839149fd89f9fd88a6c29cf797a67114772a9d4df5f8c96b8a8a8a848a604051611659959493929190612ad5565b60405180910390a173ffffffffffffffffffffffffffffffffffffffff89166116a75773ffffffffffffffffffffffffffffffffffffffff8116600090815260158c01602052604090204290555b6116ec565b7fc554475da3c47d29ea41e4f1ba76e92dd5b4b7764dbd96e1fb0d5d1e419bcf8b8a8a8a848a6040516116e3959493929190612ad5565b60405180910390a15b509998505050505050505050565b8181018281101561135b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad90612846565b6000846000015173ffffffffffffffffffffffffffffffffffffffff16856040015173ffffffffffffffffffffffffffffffffffffffff161415611799576117928b8a8a886020015189604001518a606001518c8b8b6119d9565b90506117b8565b6117b58b89876040015188606001518a8a600001518a8a611b5c565b90505b81806117c15750805b6117f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad906128eb565b801561184d577fa1af8cedfbd157f967dd83203fd025ece9cd1ee0f63f38632b24f1e03778bc288a8a8a8a89604001518a606001518c6040516118409796959493929190612b15565b60405180910390a1611899565b7f7cfb0fa39777da32fa26ee2f1cb14cc1c1ecd01e99d1d6bba446143f96db036f8a8a8a8a89604001518a606001518c6040516118909796959493929190612b15565b60405180910390a15b9a9950505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600a8301602052604090205461ffff168061190a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061276a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b600082611941575060016113bd565b60006119628573ffffffffffffffffffffffffffffffffffffffff16611c25565b90508073ffffffffffffffffffffffffffffffffffffffff1684849060405161198a90611c25565b600060405180830381858888f193505050503d80600081146119c8576040519150601f19603f3d011682016040523d82523d6000602084013e6119cd565b606091505b50909695505050505050565b6000836119e857506001611b4f565b6119f28a87611c28565b6119fe57506000611b4f565b6000876001811115611a0c57fe5b1415611aaf576040517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169063f242432a908490611a6e9030908d908b908b908b906004016124b9565b600060405180830381600088803b158015611a8857600080fd5b5087f193505050508015611a9a575060015b611aa657506000611aaa565b5060015b611b4f565b6001876001811115611abd57fe5b1415611b1d576040517fb88d4fde00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169063b88d4fde908490611a6e9030908d908b908a90600401612470565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ad9061280f565b9998505050505050505050565b600084611b6b57506001611c19565b611b758988611c28565b611b8157506000611c19565b6040517f2f680ebe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff881690632f680ebe908490611bdd908c908b908b908b908b90600401612536565b600060405180830381600088803b158015611bf757600080fd5b5087f193505050508015611c09575060015b611c1557506000611c19565b5060015b98975050505050505050565b90565b600073ffffffffffffffffffffffffffffffffffffffff821630148015906113bd5750506005919091015473ffffffffffffffffffffffffffffffffffffffff9081169116141590565b600082601f830112611c82578081fd5b81356020611c97611c9283612b8d565b612b69565b8281528181019085830183850287018401881015611cb3578586fd5b855b85811015611cda578135611cc881612bab565b84529284019290840190600101611cb5565b5090979650505050505050565b600082601f830112611cf7578081fd5b81356020611d07611c9283612b8d565b8281528181019085830183850287018401881015611d23578586fd5b855b85811015611cda57611d3682611da2565b84529284019290840190600101611d25565b600082601f830112611d58578081fd5b81356020611d68611c9283612b8d565b8281528181019085830183850287018401881015611d84578586fd5b855b85811015611cda57813584529284019290840190600101611d86565b80356002811061130657600080fd5b600060a08284031215611dc2578081fd5b60405160a0810181811067ffffffffffffffff82111715611ddf57fe5b6040529050808235611df081612bab565b8152611dfe60208401611da2565b60208201526040830135611e1181612bab565b604082015260608381013590820152611e2c60808401611e5e565b60808201525092915050565b803561ffff8116811461130657600080fd5b803563ffffffff8116811461130657600080fd5b803560ff8116811461130657600080fd5b80356bffffffffffffffffffffffff8116811461130657600080fd5b600060208284031215611e9c578081fd5b81356113bd81612bab565b600060208284031215611eb8578081fd5b81516113bd81612bab565b600060a08284031215611ed4578081fd5b6113bd8383611db1565b600080600060608486031215611ef2578182fd5b833592506020840135611f0481612bab565b91506040840135611f1481612bab565b809150509250925092565b600080600080600060a08688031215611f36578283fd5b853594506020860135611f4881612bab565b93506040860135611f5881612bab565b9250611f6660608701611da2565b949793965091946080013592915050565b600080600080600080600080610180898b031215611f93578586fd5b883597506020808a0135611fa681612bab565b975060408a0135611fb681612bab565b9650611fc460608b01611e38565b955060808a0135945060a08a013567ffffffffffffffff80821115611fe7578586fd5b818c0191508c601f830112611ffa578586fd5b81358181111561200657fe5b612036847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612b69565b91508082528d8482850101111561204b578687fd5b8084840185840137810190920194909452925060c089013591506120728a60e08b01611db1565b90509295985092959890939650565b60008060008060808587031215612096578182fd5b8435935060208501356120a881612bab565b92506120b660408601611e38565b91506120c460608601611e4a565b905092959194509250565b6000806000606084860312156120e3578081fd5b83359250602084013567ffffffffffffffff80821115612101578283fd5b61210d87838801611c72565b93506040860135915080821115612122578283fd5b5061212f86828701611c72565b9150509250925092565b60008060008060008060c08789031215612151578384fd5b86359550602087013567ffffffffffffffff8082111561216f578586fd5b61217b8a838b01611c72565b96506040890135915080821115612190578586fd5b61219c8a838b01611c72565b955060608901359150808211156121b1578384fd5b6121bd8a838b01611ce7565b945060808901359150808211156121d2578384fd5b6121de8a838b01611c72565b935060a08901359150808211156121f3578283fd5b5061220089828a01611d48565b9150509295509295509295565b600080828403610b00811215612221578283fd5b83359250610ae07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082011215612255578182fd5b506020830190509250929050565b600060208284031215612274578081fd5b6113bd82611e38565b60006020828403121561228e578081fd5b5051919050565b6000602082840312156122a6578081fd5b6113bd82611e4a565b6000602082840312156122c0578081fd5b6113bd82611e6f565b61030080828437600081840152505050565b61060080828437600081840152505050565b60008151808452815b81811015612312576020818501810151868301820152016122f6565b818111156123235782602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b61ffff61236282611e38565b1682526bffffffffffffffffffffffff61237e60208301611e6f565b16602083015260408181013590830152606090810135910152565b80356123a481612bab565b73ffffffffffffffffffffffffffffffffffffffff80821684526123ca60208401611da2565b9150600282106123d657fe5b816020850152604083013591506123ec82612bab565b1660408301526060818101359083015260ff61240a60808301611e5e565b1660808301525050565b63ffffffff169052565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525083606083015260a0608083015261246560a08301846122ed565b979650505050505050565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250836040830152608060608301526124af60808301846122ed565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015283606083015260a0608083015261246560a08301846122ed565b73ffffffffffffffffffffffffffffffffffffffff93909316835261ffff91909116602083015263ffffffff16604082015260600190565b600073ffffffffffffffffffffffffffffffffffffffff808816835286602084015285604084015280851660608401525060a0608083015261246560a08301846122ed565b6020808252601c908201527f4445504f5349545f4e4f545f574954484452415741424c455f59455400000000604082015260600190565b60208082526014908201527f4e4f545f494e5f57495448445241575f4d4f4445000000000000000000000000604082015260600190565b6020808252601f908201527f494e56414c49445f494e5055545f444154415f434f4e54454e545f5552495300604082015260600190565b6020808252600a908201527f4e4f545f414e5f4e465400000000000000000000000000000000000000000000604082015260600190565b60208082526012908201527f494e56414c49445f494e5055545f444154410000000000000000000000000000604082015260600190565b6020808252601b908201527f494e56414c49445f494e5055545f444154415f4e465454595045530000000000604082015260600190565b60208082526010908201527f5452414e534645525f4641494c55524500000000000000000000000000000000604082015260600190565b6020808252600d908201527f5355425f554e444552464c4f5700000000000000000000000000000000000000604082015260600190565b6020808252600c908201527f494e56414c49445f4d4f44450000000000000000000000000000000000000000604082015260600190565b6020808252600f908201527f544f4b454e5f4e4f545f464f554e440000000000000000000000000000000000604082015260600190565b60208082526010908201527f494e53554646494349454e545f46454500000000000000000000000000000000604082015260600190565b60208082526019908201527f494e56414c49445f494e5055545f444154415f544f4b454e5300000000000000604082015260600190565b6020808252600f908201527f554e4b4e4f574e5f4e4654545950450000000000000000000000000000000000604082015260600190565b6020808252600c908201527f4144445f4f564552464c4f570000000000000000000000000000000000000000604082015260600190565b6020808252600f908201527f494e56414c49445f544f4b454e49440000000000000000000000000000000000604082015260600190565b6020808252601a908201527f494e56414c49445f494e5055545f444154415f4d494e54455253000000000000604082015260600190565b60208082526014908201527f4e46545f5452414e534645525f4641494c555245000000000000000000000000604082015260600190565b60208082526011908201527f494e56414c49445f4143434f554e544944000000000000000000000000000000604082015260600190565b6020808252601a908201527f5749544844524157414c5f414c52454144595f50454e44494e47000000000000604082015260600190565b60208082526016908201527f544f4f5f4d414e595f52455155455354535f4f50454e00000000000000000000604082015260600190565b60208082526011908201527f57495448445241574e5f414c5245414459000000000000000000000000000000604082015260600190565b91825261ffff16602082015260400190565b828152610b00810163ffffffff612a2684611e4a565b1660208301526020830135612a3a81612bab565b73ffffffffffffffffffffffffffffffffffffffff81166040840152506040830135606083015260608301356080830152612a7760808401611e4a565b612a8460a0840182612414565b5060a083013560c0830152612a9f60e0830160c08501612356565b612ab161016083016101408501612399565b612ac361020083016101e085016122db565b6113bd61080083016107e085016122c9565b60ff95909516855273ffffffffffffffffffffffffffffffffffffffff938416602086015291831660408501529091166060830152608082015260a00190565b60ff97909716875273ffffffffffffffffffffffffffffffffffffffff9586166020880152938516604087015261ffff929092166060860152909216608084015260a083019190915260c082015260e00190565b60405181810167ffffffffffffffff81118282101715612b8557fe5b604052919050565b600067ffffffffffffffff821115612ba157fe5b5060209081020190565b73ffffffffffffffffffffffffffffffffffffffff81168114612bcd57600080fd5b5056fea264697066735822122040306f4eead7414238775f7365298babdf807acb919ca99631cdb02356e7634a64736f6c63430007060033

Deployed Bytecode Sourcemap

130333:17296:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;131898:2182;;;;;;;;;;-1:-1:-1;131898:2182:0;;;;;:::i;:::-;;:::i;:::-;;141506:2070;;;;;;;;;;-1:-1:-1;141506:2070:0;;;;;:::i;:::-;;:::i;136053:1148::-;;;;;;;;;;-1:-1:-1;136053:1148:0;;;;;:::i;:::-;;:::i;134157:1888::-;;;;;;;;;;-1:-1:-1;134157:1888:0;;;;;:::i;:::-;;:::i;137209:1451::-;;;;;;;;;;-1:-1:-1;137209:1451:0;;;;;:::i;:::-;;:::i;139668:1830::-;;;;;;;;;;-1:-1:-1;139668:1830:0;;;;;:::i;:::-;;:::i;138668:992::-;;;;;;;;;;-1:-1:-1;138668:992:0;;;;;:::i;:::-;;:::i;131898:2182::-;132287:22;:1;:20;:22::i;:::-;132286:23;132278:48;;;;;;;;;;;;:::i;:::-;;;;;;;;;132478:1;132445:30;:1;:28;:30::i;:::-;:34;132437:69;;;;;;;;;;;;:::i;:::-;37708:7;132525:9;:41;;;132517:71;;;;;;;;;;;;:::i;:::-;132711:8;;;:15;132701:25;;;;;:82;;;132768:15;:7;:13;;;:15::i;:::-;132679:155;;;;;;;;;;;;:::i;:::-;132952:10;;;;:32;;;;;;;;132928:21;;132952:10;;;:30;;:32;;;;;;;;;;;;;;:10;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;132928:56;;133097:16;133084:9;:29;;133076:58;;;;;;;;;;;;:::i;:::-;133198:15;133216:31;:9;133230:16;133216:13;:31::i;:::-;133198:49;-1:-1:-1;133262:14:0;;133258:97;;133293:50;133321:10;133333:9;133293:10;;:50;:27;:50::i;:::-;;133258:97;133473:37;;;;;;;:26;;;:37;;;;;;;;:46;;;;;;;;;;:56;;;;;;:61;133451:137;;;;;;;;;;;;:::i;:::-;133703:118;;;;;;;;;;;;;;133793:15;133703:118;;;;;;;;;;;133654:37;;;;-1:-1:-1;133654:37:0;;;:26;;;:37;;;;;:46;;;;;;;;;;;;:167;;;;;;;;;;;;;;;;;;;;;;;;;;;;133920:30;;;:32;;;;;;;;-1:-1:-1;133920:32:0;;;;;;;;;;133970:102;;;;;133703:118;;133654:46;;:37;;133970:102;:::i;:::-;;;;;;;;131898:2182;;;;;;:::o;141506:2070::-;141928:15;:7;:13;;;:15::i;:::-;141923:1646;;142008:279;142041:1;142067:31;142118:4;142141:2;142162:7;142188:6;142213:9;142241:8;142268:4;142008:14;:279::i;:::-;142003:677;;142619:24;;;;;;;:20;;;:24;;;;;;;;:33;;;;;;;;;;;:45;;142657:6;142619:37;:45::i;:::-;142583:24;;;;;;;:20;;;:24;;;;;;;;:33;;;;;;;;;;:81;142003:677;141923:1646;;;142760:299;142791:1;142817:31;142868:4;142891:2;142912:7;142938:6;142963:3;142985:9;143013:8;143040:4;142760:12;:299::i;:::-;142755:803;;143456:27;;;;;;;;:23;;;:27;;;;;;;;143484:10;;143456:39;;;;;;;;;;;143496:11;;;;143456:86;;143535:6;;143456:39;;:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;143456:52:0;;;143509:9;;;;143456:63;;;;;;;;;143520:9;;;;143456:74;;;;;;;;;:78;:86::i;:::-;143358:27;;;;;;;;:23;;;:27;;;;;;;;143386:10;;143358:39;;;;;;;;;;;143398:11;;;;143358:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;143358:52:0;;;143411:9;;;;143358:63;;;;;;;;;143422:9;;;;143358:74;;;;;;;:184;142755:803;141506:2070;;;;;;;;:::o;136053:1148::-;136257:14;136274:19;:1;136287:5;136274:12;:19::i;:::-;136343:24;;;136304:36;136343:24;;;:17;;;:24;;;;;;;;:33;;;;;;;;;;136395:17;;136343:33;;-1:-1:-1;136343:33:0;136395:17;;;;;136387:63;;;;;;;;;;;;:::i;:::-;136633:32;;136613:17;;;;;;;;;136633:32;;;;136613:52;;;;136594:71;:15;:71;;;:110;;;136682:22;:1;:20;:22::i;:::-;136572:188;;;;;;;;;;;;:::i;:::-;136787:14;;136859:24;;;136773:11;136859:24;;;:17;;;:24;;;;;;;;:33;;;;;;;;;;136852:40;;;;;;136787:14;;136937:256;136859:1;136988:39;137043:5;;137083:7;137105:6;137136:1;;137126:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;137126:12:0;;137153:9;137177:5;136937:14;:256::i;:::-;;136053:1148;;;;;;:::o;134157:1888::-;134342:22;:1;:20;:22::i;:::-;134334:55;;;;;;;;;;;;:::i;:::-;134402:13;134418:29;;;;;;;;:::i;:::-;134402:45;-1:-1:-1;134458:16:0;134477:33;;;;:11;:33;:::i;:::-;134458:52;-1:-1:-1;134521:14:0;134538:31;;;;:23;;;:31;:::i;:::-;134521:48;-1:-1:-1;134580:14:0;134597:31;;;;;;;;:::i;:::-;134707:36;;;;;;;:25;;;:36;;;;;;;;:45;;;;;;;;;;;134580:48;;-1:-1:-1;134707:45:0;;:54;134699:84;;;;;;;;;;;;:::i;:::-;134943:12;;;;134886:107;;;;;:16;;:37;;:107;;134943:12;134971:11;;134886:107;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;135067:36:0;;;;;;;:25;;;:36;;;;;;;;:45;;;;;;;;;;;:52;;;;135115:4;135067:52;;;135137:15;;-1:-1:-1;135137:13:0;:15::i;:::-;135132:906;;135195:21;;;;:26;:66;;;;-1:-1:-1;135259:1:0;135225:22;;;;:15;;;:22;:::i;:::-;:36;;;135195:66;135169:138;;;;;;;;;;;;:::i;:::-;135379:293;135412:1;135438:35;135493:5;;135541:7;135379:293;;;135603:1;;135593:12;;135379:293;;135132:906;;;135705:321;135736:1;135762:31;135813:5;;135861:7;135705:321;;;;;;;;;;135913:15;;;135705:321;:::i;:::-;135957:1;;135947:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;135947:12:0;;135978:9;136006:5;135705:12;:321::i;135132:906::-;134157:1888;;;;;;:::o;137209:1451::-;137543:27;;;137504:36;137543:27;;;:20;;;:27;;;;;137504:36;137571:7;137543:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;137543:36:0;;;:43;;;;;;;;;;:50;;;;;;;;137612:17;;137543:50;;-1:-1:-1;137612:17:0;;;;;137604:63;;;;;;;;;;;;:::i;:::-;137850:32;;137830:17;;;;;;;;;137850:32;;;;137830:52;;;;137811:71;:15;:71;;;:110;;;137899:22;:1;:20;:22::i;:::-;137789:188;;;;;;;;;;;;:::i;:::-;138004:14;;138076:27;;;137990:11;138076:27;;;:20;;;:27;;;;;138004:14;;;;;138076:27;138104:7;138004:14;138076:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;138076:36:0;;;:43;;;;;;;;;;;;:50;;;;;;;;138069:57;;;;;;138169:174;;;;;;;;;;-1:-1:-1;138169:174:0;;138238:7;138069:57;138169:174;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;138169:174:0;;;;;138139:204;-1:-1:-1;138386:266:0;138413:1;138435:39;138429:46;138490:5;;138530:1;138546:6;138567:3;138530:1;;138585:12;;138386:266;;137209:1451;;;;;;;;:::o;139668:1830::-;140066:7;:14;140049:6;:13;:31;140041:70;;;;;;;;;;;;:::i;:::-;140147:8;:15;140130:6;:13;:32;140122:72;;;;;;;;;;;;:::i;:::-;140230:6;:13;140213:6;:13;:30;140205:68;;;;;;;;;;;;:::i;:::-;140309:6;:13;140292:6;:13;:30;140284:74;;;;;;;;;;;;:::i;:::-;140374:6;140369:1122;140390:6;:13;140386:1;:17;140369:1122;;;140425:13;140441:6;140448:1;140441:9;;;;;;;;;;;;;;140425:25;;140465:14;140482:7;140490:1;140482:10;;;;;;;;;;;;;;140465:27;;140507:28;140538:8;140547:1;140538:11;;;;;;;;;;;;;;140507:42;;140564:13;140580:6;140587:1;140580:9;;;;;;;;;;;;;;140564:25;;140604:13;140620:6;140627:1;140620:9;;;;;;;;;;;;;;140604:25;;140644:11;140658:1;:23;;:30;140682:5;140658:30;;;;;;;;;;;;;;;:38;140689:6;140658:38;;;;;;;;;;;;;;;:47;140697:7;140658:47;;;;;;;;;;;;;;;;;;;;;;;;;;;:54;140706:5;140658:54;;;;;;;;;;;;;;;:61;140713:5;140658:61;;;;;;;;;;;;140644:75;;140806:1;:23;;:30;140830:5;140806:30;;;;;;;;;;;;;;;:38;140837:6;140806:38;;;;;;;;;;;;;;;:47;140845:7;140806:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;140806:47:0;;;:54;;;;;;;;;;;;:61;;;;;;;;140799:68;;;140914:199;;;;;;;;;;;;-1:-1:-1;140914:199:0;;140992:7;140914:199;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;140914:199:0;;;;;;;140884:229;;-1:-1:-1;141177:302:0;;141208:1;;141228:38;;141177:302;-1:-1:-1;;140405:3:0;;;;;-1:-1:-1;140369:1122:0;;-1:-1:-1;;;;;140369:1122:0;138668:992;138904:6;:13;138887:6;:13;:30;138879:61;;;;;;;;;;;;:::i;:::-;138956:6;138951:702;138972:6;:13;138968:1;:17;138951:702;;;139007:13;139023:6;139030:1;139023:9;;;;;;;;;;;;;;139007:25;;139047:14;139064:23;139077:6;139084:1;139077:9;;;;;;;;;;;;;;139064:1;:12;;:23;;;;:::i;:::-;139116:27;;;139102:11;139116:27;;;:20;;;:27;;;;;;;;:36;;;;;;;;;;;;139232:43;;;139116:36;;-1:-1:-1;139341:300:0;139116:20;139400:43;139463:5;;139511:7;139537:6;139572:1;;139562:12;;139341:300;-1:-1:-1;;138987:3:0;;;;;-1:-1:-1;138951:702:0;;-1:-1:-1;138951:702:0;;;138668:992;;;:::o;103580:218::-;103761:25;;;:29;;;103580:218::o;104013:243::-;104218:30;;;;;;37503:4;104178:70;104013:243;;;;:::o;106409:176::-;38456:7;106535:42;;;;;106409:176;;;:::o;43502:193::-;43610:4;43645:1;43640;:6;;43632:32;;;;;;;;;;;;:::i;:::-;-1:-1:-1;43682:5:0;;;43502:193;;;;;:::o;1908:269::-;2054:12;2094:28;:10;;;2105:6;2113:8;2094:10;:28::i;:::-;2084:38;;2141:7;2133:36;;;;;;;;;;;;:::i;:::-;1908:269;;;;;:::o;144011:1610::-;144480:12;144587:16;;;144583:83;;144625:1;:10;;;;;;;;;;;;:27;;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;144620:34;;144583:83;144692:26;;;;;144676:13;;144692:17;;;;:26;;:1;;144710:7;;144692:26;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;144676:42;-1:-1:-1;144806:12:0;;144802:280;;144839:17;;;;:77;;;;;:17;;;;;:26;;144871:8;;144839:77;;144881:4;;144887:2;;144891:5;;144898:6;;144906:9;;144839:77;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;144835:188;;145002:5;144992:15;;144835:188;;;144946:4;144936:14;;144835:188;144802:280;;;145065:5;145055:15;;144802:280;145102:12;:23;;;;145118:7;145102:23;145094:52;;;;;;;;;;;;:::i;:::-;145163:7;145159:455;;;145192:54;145212:8;145222:4;145228:2;145232:5;145239:6;145192:54;;;;;;;;;;:::i;:::-;;;;;;;;145404:18;;;145400:114;;145443:37;;;;;;;:30;;;:37;;;;;145483:15;145443:55;;145400:114;145159:455;;;145551:51;145568:8;145578:4;145584:2;145588:5;145595:6;145551:51;;;;;;;;;;:::i;:::-;;;;;;;;145159:455;144011:1610;;;;;;;;;;;;:::o;43703:191::-;43839:5;;;43863:6;;;;43855:31;;;;;;;;;;;;:::i;146009:1617::-;146517:12;146564:3;:10;;;146551:23;;:3;:9;;;:23;;;146547:749;;;146661:265;146700:1;146720:4;146743:2;146764:3;:11;;;146794:3;:9;;;146822:3;:9;;;146850:6;146875:9;146903:8;146661:20;:265::i;:::-;146651:275;;146547:749;;;147041:243;147082:1;147102:2;147123:3;:9;;;147151:3;:9;;;147179:6;147204:3;:10;;;147233:9;147261:8;147041:22;:243::i;:::-;147031:253;;146547:749;147316:12;:23;;;;147332:7;147316:23;147308:56;;;;;;;;;;;;:::i;:::-;147381:7;147377:242;;;147410:81;147433:8;147443:4;147449:2;147453:7;147462:3;:9;;;147473:3;:9;;;147484:6;147410:81;;;;;;;;;;;;:::i;:::-;;;;;;;;147377:242;;;147529:78;147549:8;147559:4;147565:2;147569:7;147578:3;:9;;;147589:3;:9;;;147600:6;147529:78;;;;;;;;;;;;:::i;:::-;;;;;;;;147377:242;146009:1617;;;;;;;;;;;;:::o;106071:330::-;106280:30;;;106238:14;106280:30;;;:16;;;:30;;;;;;;;106329:12;106321:40;;;;;;;;;;;;:::i;:::-;106382:11;;;106071:330;-1:-1:-1;;106071:330:0:o;1358:395::-;1495:12;1529:11;1525:55;;-1:-1:-1;1564:4:0;1557:11;;1525:55;1590:25;1618:14;:2;:12;;;:14::i;:::-;1590:42;;1697:9;:14;;1719:6;1732:8;1697:48;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1683:62:0;;1358:395;-1:-1:-1;;;;;;1358:395:0:o;127423:1433::-;127833:12;127867:11;127863:55;;-1:-1:-1;127902:4:0;127895:11;;127863:55;127981:30;:1;128005:5;127981:23;:30::i;:::-;127977:75;;-1:-1:-1;128035:5:0;128028:12;;127977:75;128079:28;128068:7;:39;;;;;;;;;128064:785;;;128128:192;;;;;:32;;;;;;128166:8;;128128:192;;128202:4;;128226:2;;128247:5;;128271:6;;128296:9;;128128:192;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;128124:303;;-1:-1:-1;128406:5:0;128124:303;;;-1:-1:-1;128350:4:0;128124:303;128064:785;;;128459:27;128448:7;:38;;;;;;;;;128444:405;;;128507:166;;;;;:31;;;;;;128544:8;;128507:166;;128580:4;;128604:2;;128625:5;;128649:9;;128507:166;;;:::i;128444:405::-;128812:25;;;;;;;;;;:::i;128444:405::-;127423:1433;;;;;;;;;;;:::o;128864:907::-;129277:12;129311:11;129307:55;;-1:-1:-1;129346:4:0;129339:11;;129307:55;129425:30;:1;129449:5;129425:23;:30::i;:::-;129421:75;;-1:-1:-1;129479:5:0;129472:12;;129421:75;129512:161;;;;;:32;;;;;;129550:8;;129512:161;;129574:2;;129591:5;;129611:6;;129632;;129653:9;;129512:161;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;129508:256;;-1:-1:-1;129747:5:0;129508:256;;;-1:-1:-1;129699:4:0;129508:256;128864:907;;;;;;;;;;:::o;1043:164::-;1194:4;1043:164::o;129779:280::-;129953:10;129989:22;;;130006:4;129989:22;;;;:61;;-1:-1:-1;;130032:17:0;;;;;;;;;;130015:35;;;;;129779:280::o;14:782:1:-;;127:3;120:4;112:6;108:17;104:27;94:2;;149:5;142;135:20;94:2;189:6;176:20;215:4;239:65;254:49;300:2;254:49;:::i;:::-;239:65;:::i;:::-;338:15;;;369:12;;;;401:15;;;447:11;;;435:24;;431:33;;428:42;-1:-1:-1;425:2:1;;;487:5;480;473:20;425:2;513:5;527:240;541:2;538:1;535:9;527:240;;;612:3;599:17;629:33;656:5;629:33;:::i;:::-;675:18;;713:12;;;;745;;;;559:1;552:9;527:240;;;-1:-1:-1;785:5:1;;84:712;-1:-1:-1;;;;;;;84:712:1:o;801:725::-;;920:3;913:4;905:6;901:17;897:27;887:2;;942:5;935;928:20;887:2;982:6;969:20;1008:4;1032:65;1047:49;1093:2;1047:49;:::i;1032:65::-;1131:15;;;1162:12;;;;1194:15;;;1240:11;;;1228:24;;1224:33;;1221:42;-1:-1:-1;1218:2:1;;;1280:5;1273;1266:20;1218:2;1306:5;1320:177;1334:2;1331:1;1328:9;1320:177;;;1391:31;1418:3;1391:31;:::i;:::-;1379:44;;1443:12;;;;1475;;;;1352:1;1345:9;1320:177;;1531:705;;1644:3;1637:4;1629:6;1625:17;1621:27;1611:2;;1666:5;1659;1652:20;1611:2;1706:6;1693:20;1732:4;1756:65;1771:49;1817:2;1771:49;:::i;1756:65::-;1855:15;;;1886:12;;;;1918:15;;;1964:11;;;1952:24;;1948:33;;1945:42;-1:-1:-1;1942:2:1;;;2004:5;1997;1990:20;1942:2;2030:5;2044:163;2058:2;2055:1;2052:9;2044:163;;;2115:17;;2103:30;;2153:12;;;;2185;;;;2076:1;2069:9;2044:163;;2241:151;2317:20;;2366:1;2356:12;;2346:2;;2382:1;2379;2372:12;2397:840;;2498:4;2486:9;2481:3;2477:19;2473:30;2470:2;;;2520:5;2513;2506:20;2470:2;2557;2551:9;2599:4;2591:6;2587:17;2670:6;2658:10;2655:22;2634:18;2622:10;2619:34;2616:62;2613:2;;;2681:9;2613:2;2708;2701:22;2741:6;-1:-1:-1;2741:6:1;2771:23;;2803:35;2771:23;2803:35;:::i;:::-;2847:23;;2903:46;2945:2;2930:18;;2903:46;:::i;:::-;2898:2;2890:6;2886:15;2879:71;3002:2;2991:9;2987:18;2974:32;3015:35;3042:7;3015:35;:::i;:::-;3078:2;3066:15;;3059:32;3152:2;3137:18;;;3124:32;3107:15;;;3100:57;3191:39;3225:3;3210:19;;3191:39;:::i;:::-;3185:3;3177:6;3173:16;3166:65;;2460:777;;;;:::o;3242:161::-;3311:20;;3371:6;3360:18;;3350:29;;3340:2;;3393:1;3390;3383:12;3408:165;3477:20;;3537:10;3526:22;;3516:33;;3506:2;;3563:1;3560;3553:12;3578:158;3646:20;;3706:4;3695:16;;3685:27;;3675:2;;3726:1;3723;3716:12;3741:181;3810:20;;3870:26;3859:38;;3849:49;;3839:2;;3912:1;3909;3902:12;3927:259;;4039:2;4027:9;4018:7;4014:23;4010:32;4007:2;;;4060:6;4052;4045:22;4007:2;4104:9;4091:23;4123:33;4150:5;4123:33;:::i;4191:263::-;;4314:2;4302:9;4293:7;4289:23;4285:32;4282:2;;;4335:6;4327;4320:22;4282:2;4372:9;4366:16;4391:33;4418:5;4391:33;:::i;4735:233::-;;4868:3;4856:9;4847:7;4843:23;4839:33;4836:2;;;4890:6;4882;4875:22;4836:2;4918:44;4954:7;4943:9;4918:44;:::i;4973:494::-;;;;5143:2;5131:9;5122:7;5118:23;5114:32;5111:2;;;5164:6;5156;5149:22;5111:2;5205:9;5192:23;5182:33;;5265:2;5254:9;5250:18;5237:32;5278:33;5305:5;5278:33;:::i;:::-;5330:5;-1:-1:-1;5387:2:1;5372:18;;5359:32;5400:35;5359:32;5400:35;:::i;:::-;5454:7;5444:17;;;5101:366;;;;;:::o;5472:658::-;;;;;;5688:3;5676:9;5667:7;5663:23;5659:33;5656:2;;;5710:6;5702;5695:22;5656:2;5751:9;5738:23;5728:33;;5811:2;5800:9;5796:18;5783:32;5824:33;5851:5;5824:33;:::i;:::-;5876:5;-1:-1:-1;5933:2:1;5918:18;;5905:32;5946:35;5905:32;5946:35;:::i;:::-;6000:7;-1:-1:-1;6026:46:1;6068:2;6053:18;;6026:46;:::i;:::-;5646:484;;;;-1:-1:-1;5646:484:1;;6119:3;6104:19;6091:33;;5646:484;-1:-1:-1;;5646:484:1:o;6135:1554::-;;;;;;;;;6419:3;6407:9;6398:7;6394:23;6390:33;6387:2;;;6441:6;6433;6426:22;6387:2;6482:9;6469:23;6459:33;;6511:2;6563;6552:9;6548:18;6535:32;6576:33;6603:5;6576:33;:::i;:::-;6628:5;-1:-1:-1;6685:2:1;6670:18;;6657:32;6698:35;6657:32;6698:35;:::i;:::-;6752:7;-1:-1:-1;6778:39:1;6813:2;6798:18;;6778:39;:::i;:::-;6768:49;;6864:3;6853:9;6849:19;6836:33;6826:43;;6920:3;6909:9;6905:19;6892:33;6944:18;6985:2;6977:6;6974:14;6971:2;;;7006:6;6998;6991:22;6971:2;7049:6;7038:9;7034:22;7024:32;;7094:7;7087:4;7083:2;7079:13;7075:27;7065:2;;7121:6;7113;7106:22;7065:2;7162;7149:16;7184:2;7180;7177:10;7174:2;;;7190:9;7174:2;7223:111;7330:2;7261:66;7254:4;7250:2;7246:13;7242:86;7238:95;7223:111;:::i;:::-;7210:124;;7357:2;7350:5;7343:17;7397:7;7392:2;7387;7383;7379:11;7375:20;7372:33;7369:2;;;7423:6;7415;7408:22;7369:2;7483;7478;7474;7470:11;7465:2;7458:5;7454:14;7441:45;7506:14;;7502:23;;;7495:39;;;;7510:5;-1:-1:-1;7605:3:1;7590:19;;7577:33;;-1:-1:-1;7629:54:1;7675:7;7669:3;7654:19;;7629:54;:::i;:::-;7619:64;;6377:1312;;;;;;;;;;;:::o;7694:500::-;;;;;7879:3;7867:9;7858:7;7854:23;7850:33;7847:2;;;7901:6;7893;7886:22;7847:2;7942:9;7929:23;7919:33;;8002:2;7991:9;7987:18;7974:32;8015:33;8042:5;8015:33;:::i;:::-;8067:5;-1:-1:-1;8091:39:1;8126:2;8111:18;;8091:39;:::i;:::-;8081:49;;8149:39;8184:2;8173:9;8169:18;8149:39;:::i;:::-;8139:49;;7837:357;;;;;;;:::o;8199:729::-;;;;8419:2;8407:9;8398:7;8394:23;8390:32;8387:2;;;8440:6;8432;8425:22;8387:2;8481:9;8468:23;8458:33;;8542:2;8531:9;8527:18;8514:32;8565:18;8606:2;8598:6;8595:14;8592:2;;;8627:6;8619;8612:22;8592:2;8655:67;8714:7;8705:6;8694:9;8690:22;8655:67;:::i;:::-;8645:77;;8775:2;8764:9;8760:18;8747:32;8731:48;;8804:2;8794:8;8791:16;8788:2;;;8825:6;8817;8810:22;8788:2;;8853:69;8914:7;8903:8;8892:9;8888:24;8853:69;:::i;:::-;8843:79;;;8377:551;;;;;:::o;8933:1476::-;;;;;;;9291:3;9279:9;9270:7;9266:23;9262:33;9259:2;;;9313:6;9305;9298:22;9259:2;9354:9;9341:23;9331:33;;9415:2;9404:9;9400:18;9387:32;9438:18;9479:2;9471:6;9468:14;9465:2;;;9500:6;9492;9485:22;9465:2;9528:67;9587:7;9578:6;9567:9;9563:22;9528:67;:::i;:::-;9518:77;;9648:2;9637:9;9633:18;9620:32;9604:48;;9677:2;9667:8;9664:16;9661:2;;;9698:6;9690;9683:22;9661:2;9726:69;9787:7;9776:8;9765:9;9761:24;9726:69;:::i;:::-;9716:79;;9848:2;9837:9;9833:18;9820:32;9804:48;;9877:2;9867:8;9864:16;9861:2;;;9898:6;9890;9883:22;9861:2;9926:75;9993:7;9982:8;9971:9;9967:24;9926:75;:::i;:::-;9916:85;;10054:3;10043:9;10039:19;10026:33;10010:49;;10084:2;10074:8;10071:16;10068:2;;;10105:6;10097;10090:22;10068:2;10133:69;10194:7;10183:8;10172:9;10168:24;10133:69;:::i;:::-;10123:79;;10255:3;10244:9;10240:19;10227:33;10211:49;;10285:2;10275:8;10272:16;10269:2;;;10306:6;10298;10291:22;10269:2;;10334:69;10395:7;10384:8;10373:9;10369:24;10334:69;:::i;:::-;10324:79;;;9249:1160;;;;;;;;:::o;10414:447::-;;;10589:9;10580:7;10576:23;10619:4;10615:2;10611:13;10608:2;;;10642:6;10634;10627:22;10608:2;10683:9;10670:23;10660:33;;10786:4;10717:66;10713:2;10709:75;10705:86;10702:2;;;10809:6;10801;10794:22;10702:2;;10852;10841:9;10837:18;10827:28;;10556:305;;;;;:::o;10866:196::-;;10977:2;10965:9;10956:7;10952:23;10948:32;10945:2;;;10998:6;10990;10983:22;10945:2;11026:30;11046:9;11026:30;:::i;11067:194::-;;11190:2;11178:9;11169:7;11165:23;11161:32;11158:2;;;11211:6;11203;11196:22;11158:2;-1:-1:-1;11239:16:1;;11148:113;-1:-1:-1;11148:113:1:o;11266:196::-;;11377:2;11365:9;11356:7;11352:23;11348:32;11345:2;;;11398:6;11390;11383:22;11345:2;11426:30;11446:9;11426:30;:::i;11467:196::-;;11578:2;11566:9;11557:7;11553:23;11549:32;11546:2;;;11599:6;11591;11584:22;11546:2;11627:30;11647:9;11627:30;:::i;11668:165::-;11752:6;11792:2;11785:5;11780:3;11767:28;11825:1;11820:2;11815:3;11811:12;11804:23;;11732:101;;:::o;11838:169::-;11926:6;11966:2;11959:5;11954:3;11941:28;11999:1;11994:2;11989:3;11985:12;11978:23;;11906:101;;:::o;12012:536::-;;12093:5;12087:12;12120:6;12115:3;12108:19;12145:3;12157:162;12171:6;12168:1;12165:13;12157:162;;;12233:4;12289:13;;;12285:22;;12279:29;12261:11;;;12257:20;;12250:59;12186:12;12157:162;;;12337:6;12334:1;12331:13;12328:2;;;12403:3;12396:4;12387:6;12382:3;12378:16;12374:27;12367:40;12328:2;-1:-1:-1;12462:2:1;12450:15;12467:66;12446:88;12437:98;;;;12537:4;12433:109;;12063:485;-1:-1:-1;;12063:485:1:o;12553:364::-;12674:6;12646:26;12666:5;12646:26;:::i;:::-;12642:39;12637:3;12630:52;12757:26;12718:37;12749:4;12742:5;12738:16;12718:37;:::i;:::-;12714:70;12707:4;12698:14;;12691:94;12841:4;12830:16;;;12817:30;12801:14;;;12794:54;12904:4;12893:16;;;12880:30;12864:14;;12857:54;12620:297::o;12922:698::-;13019:5;13006:19;13034:35;13061:7;13034:35;:::i;:::-;13088:42;13164:2;13155:7;13151:16;13146:3;13139:29;13192:44;13230:4;13223:5;13219:16;13192:44;:::i;:::-;13177:59;;13267:1;13258:7;13255:14;13245:2;;13273:9;13245:2;13316:7;13309:4;13304:3;13300:14;13293:31;13372:4;13365:5;13361:16;13348:30;13333:45;;13387:35;13414:7;13387:35;:::i;:::-;13454:16;13447:4;13438:14;;13431:40;13527:4;13516:16;;;13503:30;13487:14;;;13480:54;13608:4;13570:36;13600:4;13589:16;;13570:36;:::i;:::-;13566:47;13559:4;13554:3;13550:14;13543:71;12981:639;;:::o;13625:96::-;13703:10;13692:22;13680:35;;13670:51::o;13936:594::-;;14187:42;14268:2;14260:6;14256:15;14245:9;14238:34;14320:2;14312:6;14308:15;14303:2;14292:9;14288:18;14281:43;14372:2;14364:6;14360:15;14355:2;14344:9;14340:18;14333:43;;14412:6;14407:2;14396:9;14392:18;14385:34;14456:3;14450;14439:9;14435:19;14428:32;14477:47;14519:3;14508:9;14504:19;14496:6;14477:47;:::i;:::-;14469:55;14167:363;-1:-1:-1;;;;;;;14167:363:1:o;14535:513::-;;14758:42;14839:2;14831:6;14827:15;14816:9;14809:34;14891:2;14883:6;14879:15;14874:2;14863:9;14859:18;14852:43;;14931:6;14926:2;14915:9;14911:18;14904:34;14974:3;14969:2;14958:9;14954:18;14947:31;14995:47;15037:3;15026:9;15022:19;15014:6;14995:47;:::i;:::-;14987:55;14738:310;-1:-1:-1;;;;;;14738:310:1:o;15053:585::-;;15304:42;15385:2;15377:6;15373:15;15362:9;15355:34;15437:2;15429:6;15425:15;15420:2;15409:9;15405:18;15398:43;;15477:6;15472:2;15461:9;15457:18;15450:34;15520:6;15515:2;15504:9;15500:18;15493:34;15564:3;15558;15547:9;15543:19;15536:32;15585:47;15627:3;15616:9;15612:19;15604:6;15585:47;:::i;15643:394::-;15871:42;15859:55;;;;15841:74;;15963:6;15951:19;;;;15946:2;15931:18;;15924:47;16019:10;16007:23;16002:2;15987:18;;15980:51;15829:2;15814:18;;15796:241::o;16042:585::-;;16293:42;16374:2;16366:6;16362:15;16351:9;16344:34;16414:6;16409:2;16398:9;16394:18;16387:34;16457:6;16452:2;16441:9;16437:18;16430:34;16512:2;16504:6;16500:15;16495:2;16484:9;16480:18;16473:43;;16553:3;16547;16536:9;16532:19;16525:32;16574:47;16616:3;16605:9;16601:19;16593:6;16574:47;:::i;16632:352::-;16834:2;16816:21;;;16873:2;16853:18;;;16846:30;16912;16907:2;16892:18;;16885:58;16975:2;16960:18;;16806:178::o;16989:344::-;17191:2;17173:21;;;17230:2;17210:18;;;17203:30;17269:22;17264:2;17249:18;;17242:50;17324:2;17309:18;;17163:170::o;17338:355::-;17540:2;17522:21;;;17579:2;17559:18;;;17552:30;17618:33;17613:2;17598:18;;17591:61;17684:2;17669:18;;17512:181::o;17698:334::-;17900:2;17882:21;;;17939:2;17919:18;;;17912:30;17978:12;17973:2;17958:18;;17951:40;18023:2;18008:18;;17872:160::o;18037:342::-;18239:2;18221:21;;;18278:2;18258:18;;;18251:30;18317:20;18312:2;18297:18;;18290:48;18370:2;18355:18;;18211:168::o;18384:351::-;18586:2;18568:21;;;18625:2;18605:18;;;18598:30;18664:29;18659:2;18644:18;;18637:57;18726:2;18711:18;;18558:177::o;18740:340::-;18942:2;18924:21;;;18981:2;18961:18;;;18954:30;19020:18;19015:2;19000:18;;18993:46;19071:2;19056:18;;18914:166::o;19085:337::-;19287:2;19269:21;;;19326:2;19306:18;;;19299:30;19365:15;19360:2;19345:18;;19338:43;19413:2;19398:18;;19259:163::o;19427:336::-;19629:2;19611:21;;;19668:2;19648:18;;;19641:30;19707:14;19702:2;19687:18;;19680:42;19754:2;19739:18;;19601:162::o;19768:339::-;19970:2;19952:21;;;20009:2;19989:18;;;19982:30;20048:17;20043:2;20028:18;;20021:45;20098:2;20083:18;;19942:165::o;20112:340::-;20314:2;20296:21;;;20353:2;20333:18;;;20326:30;20392:18;20387:2;20372:18;;20365:46;20443:2;20428:18;;20286:166::o;20457:349::-;20659:2;20641:21;;;20698:2;20678:18;;;20671:30;20737:27;20732:2;20717:18;;20710:55;20797:2;20782:18;;20631:175::o;20811:339::-;21013:2;20995:21;;;21052:2;21032:18;;;21025:30;21091:17;21086:2;21071:18;;21064:45;21141:2;21126:18;;20985:165::o;21155:336::-;21357:2;21339:21;;;21396:2;21376:18;;;21369:30;21435:14;21430:2;21415:18;;21408:42;21482:2;21467:18;;21329:162::o;21496:339::-;21698:2;21680:21;;;21737:2;21717:18;;;21710:30;21776:17;21771:2;21756:18;;21749:45;21826:2;21811:18;;21670:165::o;21840:350::-;22042:2;22024:21;;;22081:2;22061:18;;;22054:30;22120:28;22115:2;22100:18;;22093:56;22181:2;22166:18;;22014:176::o;22195:344::-;22397:2;22379:21;;;22436:2;22416:18;;;22409:30;22475:22;22470:2;22455:18;;22448:50;22530:2;22515:18;;22369:170::o;22544:341::-;22746:2;22728:21;;;22785:2;22765:18;;;22758:30;22824:19;22819:2;22804:18;;22797:47;22876:2;22861:18;;22718:167::o;22890:350::-;23092:2;23074:21;;;23131:2;23111:18;;;23104:30;23170:28;23165:2;23150:18;;23143:56;23231:2;23216:18;;23064:176::o;23245:346::-;23447:2;23429:21;;;23486:2;23466:18;;;23459:30;23525:24;23520:2;23505:18;;23498:52;23582:2;23567:18;;23419:172::o;23596:341::-;23798:2;23780:21;;;23837:2;23817:18;;;23810:30;23876:19;23871:2;23856:18;;23849:47;23928:2;23913:18;;23770:167::o;23942:291::-;24146:25;;;24219:6;24207:19;24202:2;24187:18;;24180:47;24134:2;24119:18;;24101:132::o;24238:1216::-;24482:25;;;24468:4;24453:20;;24576:10;24547:27;24567:6;24547:27;:::i;:::-;24543:44;24538:2;24527:9;24523:18;24516:72;24635:2;24627:6;24623:15;24610:29;24648:33;24675:5;24648:33;:::i;:::-;24728:42;24721:5;24717:54;24712:2;24701:9;24697:18;24690:82;;24833:2;24825:6;24821:15;24808:29;24803:2;24792:9;24788:18;24781:57;24900:2;24892:6;24888:15;24875:29;24869:3;24858:9;24854:19;24847:58;24929:37;24961:3;24953:6;24949:16;24929:37;:::i;:::-;24975:49;25019:3;25008:9;25004:19;24995:7;24975:49;:::i;:::-;;25086:3;25078:6;25074:16;25061:30;25055:3;25044:9;25040:19;25033:59;25101:80;25176:3;25165:9;25161:19;25155:3;25147:6;25143:16;25101:80;:::i;:::-;25190:75;25260:3;25249:9;25245:19;25236:6;25228;25224:19;25190:75;:::i;:::-;25274:84;25353:3;25342:9;25338:19;25329:6;25321;25317:19;25274:84;:::i;:::-;25367:81;25442:4;25431:9;25427:20;25418:6;25410;25406:19;25367:81;:::i;25459:558::-;25744:4;25732:17;;;;25714:36;;25769:42;25847:15;;;25842:2;25827:18;;25820:43;25899:15;;;25894:2;25879:18;;25872:43;25951:15;;;25946:2;25931:18;;25924:43;25998:3;25983:19;;25976:35;25701:3;25686:19;;25668:349::o;26022:713::-;26361:4;26349:17;;;;26331:36;;26386:42;26464:15;;;26459:2;26444:18;;26437:43;26516:15;;;26511:2;26496:18;;26489:43;26580:6;26568:19;;;;26563:2;26548:18;;26541:47;26625:15;;;26619:3;26604:19;;26597:44;26672:3;26657:19;;26650:35;;;;26716:3;26701:19;;26694:35;26318:3;26303:19;;26285:450::o;26740:242::-;26810:2;26804:9;26840:17;;;26887:18;26872:34;;26908:22;;;26869:62;26866:2;;;26934:9;26866:2;26961;26954:22;26784:198;;-1:-1:-1;26784:198:1:o;26987:183::-;;27086:18;27078:6;27075:30;27072:2;;;27108:9;27072:2;-1:-1:-1;27159:4:1;27140:17;;;27136:28;;27062:108::o;27175:156::-;27263:42;27256:5;27252:54;27245:5;27242:65;27232:2;;27321:1;27318;27311:12;27232:2;27222:109;:::o

Swarm Source

ipfs://40306f4eead7414238775f7365298babdf807acb919ca99631cdb02356e7634a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.