Bokuto Testnet

Contract

0x35B90F99680C426bf6753a78C364B045115cb46e
Source Code Source Code

Overview

ETH Balance

0 ETH

More Info

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Amount

There are no matching entries

Please try again later

Parent Transaction Hash Block From To Amount
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RapidityLibV4

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

import "./RapidityTxLib.sol";
import "./CrossTypes.sol";
import "../../interfaces/ITokenManager.sol";
import "../../interfaces/IRC20Protocol.sol";
import "./EtherTransfer.sol";

/**
 * @title RapidityLibV4
 * @dev Library for managing rapid cross-chain token transfers
 * This library provides functionality for:
 * - Token locking and unlocking
 * - Token minting and burning
 * - Cross-chain token transfer management
 */
library RapidityLibV4 {
    using SafeMath for uint;
    using RapidityTxLib for RapidityTxLib.Data;

    /**
     * @notice Enumeration of supported token types for cross-chain operations
     * @dev Defines the types of tokens that can be transferred across chains
     */
    enum TokenCrossType {ERC20, ERC721, ERC1155}

    /**
     * @notice Parameters for user-initiated token locking operations
     * @dev Used when users want to lock their tokens for cross-chain transfer
     * @param smgID ID of the selected storeman group
     * @param tokenPairID ID of the token pair for cross-chain transfer
     * @param value Amount of tokens to transfer
     * @param currentChainID ID of the current blockchain
     * @param tokenPairContractFee Fee for the token pair contract
     * @param etherTransferGasLimit Gas limit for ether transfers
     * @param destUserAccount Destination user account address
     * @param smgFeeProxy Address of the proxy for storing storeman group fees
     */
    struct RapidityUserLockParams {
        bytes32 smgID;
        uint tokenPairID;
        uint value;
        uint currentChainID;
        uint tokenPairContractFee;
        uint etherTransferGasLimit;
        bytes destUserAccount;
        address smgFeeProxy;
    }

    /**
     * @notice Parameters for storeman-initiated token minting operations
     * @dev Used when storeman group mints tokens on the destination chain
     * @param uniqueID Unique identifier for the rapidity transaction
     * @param smgID ID of the storeman group
     * @param tokenPairID ID of the token pair
     * @param value Amount of tokens to mint
     * @param fee Transaction fee
     * @param destTokenAccount Destination token contract address
     * @param destUserAccount Destination user account address
     * @param smgFeeProxy Address of the proxy for storing storeman group fees
     */
    struct RapiditySmgMintParams {
        bytes32 uniqueID;
        bytes32 smgID;
        uint tokenPairID;
        uint value;
        uint fee;
        address destTokenAccount;
        address destUserAccount;
        address smgFeeProxy;
    }

    /**
     * @notice Parameters for user-initiated token burning operations
     * @dev Used when users want to burn their tokens for cross-chain transfer
     * @param smgID ID of the selected storeman group
     * @param tokenPairID ID of the token pair
     * @param value Amount of tokens to burn
     * @param currentChainID ID of the current blockchain
     * @param fee Transaction fee
     * @param tokenPairContractFee Fee for the token pair contract
     * @param etherTransferGasLimit Gas limit for ether transfers
     * @param srcTokenAccount Source token contract address
     * @param destUserAccount Destination user account address
     * @param smgFeeProxy Address of the proxy for storing storeman group fees
     */
    struct RapidityUserBurnParams {
        bytes32 smgID;
        uint tokenPairID;
        uint value;
        uint currentChainID;
        uint fee;
        uint tokenPairContractFee;
        uint etherTransferGasLimit;
        address srcTokenAccount;
        bytes destUserAccount;
        address smgFeeProxy;
    }

    /**
     * @notice Parameters for storeman-initiated token release operations
     * @dev Used when storeman group releases tokens on the original chain
     * @param uniqueID Unique identifier for the rapidity transaction
     * @param smgID ID of the storeman group
     * @param tokenPairID ID of the token pair
     * @param value Amount of tokens to release
     * @param fee Transaction fee
     * @param etherTransferGasLimit Gas limit for ether transfers
     * @param destTokenAccount Destination token contract address
     * @param destUserAccount Destination user account address
     * @param smgFeeProxy Address of the proxy for storing storeman group fees
     */
    struct RapiditySmgReleaseParams {
        bytes32 uniqueID;
        bytes32 smgID;
        uint tokenPairID;
        uint value;
        uint fee;
        uint etherTransferGasLimit;
        address destTokenAccount;
        address destUserAccount;
        address smgFeeProxy;
    }

    /**
     * @notice Event emitted when tokens are locked by a user
     * @param smgID ID of the storeman group
     * @param tokenPairID ID of the token pair
     * @param tokenAccount Address of the token contract
     * @param value Amount of tokens locked
     * @param contractFee Contract fee charged
     * @param userAccount Destination user account address
     */
    event UserLockLogger(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, uint value, uint contractFee, bytes userAccount);

    /**
     * @notice Event emitted when tokens are burned by a user
     * @param smgID ID of the storeman group
     * @param tokenPairID ID of the token pair
     * @param tokenAccount Address of the token contract
     * @param value Amount of tokens burned
     * @param contractFee Contract fee charged
     * @param fee Transaction fee charged
     * @param userAccount Destination user account address
     */
    event UserBurnLogger(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, uint value, uint contractFee, uint fee, bytes userAccount);

    /**
     * @notice Event emitted when tokens are minted by storeman group
     * @param uniqueID Unique identifier for the rapidity transaction
     * @param smgID ID of the storeman group
     * @param tokenPairID ID of the token pair
     * @param value Amount of tokens minted
     * @param tokenAccount Address of the token contract
     * @param userAccount Destination user account address
     */
    event SmgMintLogger(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, uint value, address tokenAccount, address userAccount);

    /**
     * @notice Event emitted when tokens are minted by storeman group (with additional data)
     * @param uniqueID Unique identifier for the rapidity transaction
     * @param smgID ID of the storeman group
     * @param tokenPairID ID of the token pair
     * @param keys Array of event keys
     * @param values Array of event values
     */
    event SmgMint(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, string[] keys, bytes[] values);

    /**
     * @notice Event emitted when tokens are released by storeman group
     * @param uniqueID Unique identifier for the rapidity transaction
     * @param smgID ID of the storeman group
     * @param tokenPairID ID of the token pair
     * @param value Amount of tokens released
     * @param tokenAccount Address of the token contract
     * @param userAccount Destination user account address
     */
    event SmgReleaseLogger(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, uint value, address tokenAccount, address userAccount);

    /**
     * @notice Event emitted when tokens are released by storeman group (with additional data)
     * @param uniqueID Unique identifier for the rapidity transaction
     * @param smgID ID of the storeman group
     * @param tokenPairID ID of the token pair
     * @param keys Array of event keys
     * @param values Array of event values
     */
    event SmgRelease(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, string[] keys, bytes[] values);

    /**
     * @notice Locks tokens for cross-chain transfer
     * @dev Handles the locking of ERC20 tokens
     * @param storageData Cross storage data
     * @param params Parameters for the token locking operation
     * Requirements:
     * - Token type must be ERC20
     * - User must have sufficient balance
     * - Contract must have approval to transfer tokens
     */
    function userLock(CrossTypes.Data storage storageData, RapidityUserLockParams memory params)
    public
    {
        ITokenManager tokenManager = storageData.tokenManager;
        uint fromChainID;
        uint toChainID;
        bytes memory fromTokenAccount;
        bytes memory toTokenAccount;
        (fromChainID,fromTokenAccount,toChainID,toTokenAccount) = tokenManager.getTokenPairInfo(params.tokenPairID);
        require(fromChainID != 0, "Token does not exist");

        uint contractFee = params.tokenPairContractFee;
        address tokenScAddr;
        if (params.currentChainID == fromChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[fromChainID][toChainID];
            }
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[fromChainID][0];
            }
            tokenScAddr = CrossTypes.bytesToAddress(fromTokenAccount);
        } else if (params.currentChainID == toChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[toChainID][fromChainID];
            }
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[toChainID][0];
            }
            tokenScAddr = CrossTypes.bytesToAddress(toTokenAccount);
        } else {
            require(false, "Invalid token pair");
        }
        if (contractFee > 0) {
            EtherTransfer.sendValue(payable(params.smgFeeProxy), contractFee, params.etherTransferGasLimit);
        }

        uint left;
        if (tokenScAddr == address(0)) {
            left = (msg.value).sub(params.value).sub(contractFee);
        } else {
            left = (msg.value).sub(contractFee);

            uint8 tokenCrossType = tokenManager.mapTokenPairType(params.tokenPairID);
            require(tokenCrossType == uint8(TokenCrossType.ERC20), "Not support");
            require(CrossTypes.transferFrom(tokenScAddr, msg.sender, address(this), params.value), "Lock token failed");
        }
        if (left != 0) {
            EtherTransfer.sendValue(payable(msg.sender), left, params.etherTransferGasLimit);
        }
        emit UserLockLogger(params.smgID, params.tokenPairID, tokenScAddr, params.value, contractFee, params.destUserAccount);
    }

    /**
     * @notice Burns tokens for cross-chain transfer
     * @dev Handles the burning of ERC20 tokens
     * @param storageData Cross storage data
     * @param params Parameters for the token burning operation
     * Requirements:
     * - Token type must be ERC20
     * - User must have sufficient balance
     * - Contract must have approval to burn tokens
     */
    function userBurn(CrossTypes.Data storage storageData, RapidityUserBurnParams memory params)
    public
    {
        ITokenManager tokenManager = storageData.tokenManager;
        uint fromChainID;
        uint toChainID;
        bytes memory fromTokenAccount;
        bytes memory toTokenAccount;
        (fromChainID,fromTokenAccount,toChainID,toTokenAccount) = tokenManager.getTokenPairInfo(params.tokenPairID);
        require(fromChainID != 0, "Token does not exist");

        uint256 contractFee = params.tokenPairContractFee;
        address tokenScAddr;
        if (params.currentChainID == toChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[toChainID][fromChainID];
            }
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[toChainID][0];
            }
            tokenScAddr = CrossTypes.bytesToAddress(toTokenAccount);
        } else if (params.currentChainID == fromChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[fromChainID][toChainID];
            }
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[fromChainID][0];
            }
            tokenScAddr = CrossTypes.bytesToAddress(fromTokenAccount);
        } else {
            require(false, "Invalid token pair");
        }
        require(params.srcTokenAccount == tokenScAddr, "Invalid token account");

        // Reuse variable fromChainID as tokenCrossType; burn token by tokenCrossType
        fromChainID = tokenManager.mapTokenPairType(params.tokenPairID);
        require(fromChainID == uint8(TokenCrossType.ERC20), "Not support");
        require(burnShadowToken(tokenManager, tokenScAddr, msg.sender, params.value), "Burn failed");

        if (contractFee > 0) {
            EtherTransfer.sendValue(payable(params.smgFeeProxy), contractFee, params.etherTransferGasLimit);
        }

        uint left = (msg.value).sub(contractFee);
        if (left != 0) {
            EtherTransfer.sendValue(payable(msg.sender), left, params.etherTransferGasLimit);
        }

        emit UserBurnLogger(params.smgID, params.tokenPairID, tokenScAddr, params.value, contractFee, params.fee, params.destUserAccount);
    }

    /**
     * @notice Mints tokens on the destination chain
     * @dev Handles the minting of ERC20 tokens
     * @param storageData Cross storage data
     * @param params Parameters for the token minting operation
     * Requirements:
     * - Token type must be valid (ERC20)
     * - Storeman group must have permission to mint
     */
    function smgMint(CrossTypes.Data storage storageData, RapiditySmgMintParams memory params)
    public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        ITokenManager tokenManager = storageData.tokenManager;
        uint8 tokenCrossType = tokenManager.mapTokenPairType(params.tokenPairID);
        require(tokenCrossType == uint8(TokenCrossType.ERC20), "Not support");
        if (params.fee > 0) {
            require(mintShadowToken(tokenManager, params.destTokenAccount, params.smgFeeProxy, params.fee), "Mint fee failed");
        }
        require(mintShadowToken(tokenManager, params.destTokenAccount, params.destUserAccount, params.value), "Mint failed");

        string[] memory keys = new string[](4);
        bytes[] memory values = new bytes[](4);
        keys[0] = "value:uint256";
        values[0] = abi.encodePacked(params.value);
        keys[1] = "tokenAccount:address";
        values[1] = abi.encodePacked(params.destTokenAccount);
        keys[2] = "userAccount:address";
        values[2] = abi.encodePacked(params.destUserAccount);
        keys[3] = "fee:uint256";
        values[3] = abi.encodePacked(params.fee);
        emit SmgMint(params.uniqueID, params.smgID, params.tokenPairID, keys, values);
        emit SmgMintLogger(params.uniqueID, params.smgID, params.tokenPairID, params.value, params.destTokenAccount, params.destUserAccount);
    }

    /**
     * @notice Releases tokens on the original chain
     * @dev Handles the release of ERC20 tokens
     * @param storageData Cross storage data
     * @param params Parameters for the token release operation
     * Requirements:
     * - Token type must be ERC20
     * - Storeman group must have permission to release
     */
    function smgRelease(CrossTypes.Data storage storageData, RapiditySmgReleaseParams memory params)
    public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        if (params.destTokenAccount == address(0)) {
            EtherTransfer.sendValue(payable(params.destUserAccount), params.value, params.etherTransferGasLimit);
            if (params.fee > 0) {
                EtherTransfer.sendValue(payable(params.smgFeeProxy), params.fee, params.etherTransferGasLimit);
            }
        } else {
            uint8 tokenCrossType = storageData.tokenManager.mapTokenPairType(params.tokenPairID);
            require(tokenCrossType == uint8(TokenCrossType.ERC20), "Not support");
            if (params.fee > 0) {
                require(CrossTypes.transfer(params.destTokenAccount, params.smgFeeProxy, params.fee), "Transfer token fee failed");
            }
            require(CrossTypes.transfer(params.destTokenAccount, params.destUserAccount, params.value), "Transfer token failed");
        }

        string[] memory keys = new string[](4);
        bytes[] memory values = new bytes[](4);
        keys[0] = "value:uint256";
        values[0] = abi.encodePacked(params.value);
        keys[1] = "tokenAccount:address";
        values[1] = abi.encodePacked(params.destTokenAccount);
        keys[2] = "userAccount:address";
        values[2] = abi.encodePacked(params.destUserAccount);
        keys[3] = "fee:uint256";
        values[3] = abi.encodePacked(params.fee);
        emit SmgRelease(params.uniqueID, params.smgID, params.tokenPairID, keys, values);
        emit SmgReleaseLogger(params.uniqueID, params.smgID, params.tokenPairID, params.value, params.destTokenAccount, params.destUserAccount);
    }

    /**
     * @notice Burns shadow tokens
     * @dev Handles the burning of ERC20 tokens
     * @param tokenManager Token manager contract
     * @param tokenAddress Address of the token contract
     * @param userAccount Address of the user account
     * @param value Amount of tokens to burn
     * @return bool indicating whether the burn was successful
     */
    function burnShadowToken(ITokenManager tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        tokenManager.burnToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.sub(value);
    }

    /**
     * @notice Mints shadow tokens
     * @dev Handles the minting of ERC20 tokens
     * @param tokenManager Token manager contract
     * @param tokenAddress Address of the token contract
     * @param userAccount Address of the user account
     * @param value Amount of tokens to mint
     * @return bool indicating whether the mint was successful
     */
    function mintShadowToken(ITokenManager tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        tokenManager.mintToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.add(value);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

import "../../interfaces/IRC20Protocol.sol";
import "../../interfaces/IQuota.sol";
import "../../interfaces/IStoremanGroup.sol";
import "../../interfaces/ITokenManager.sol";
import "../../interfaces/ISignatureVerifier.sol";
import "./HTLCTxLib.sol";
import "./RapidityTxLib.sol";

/**
 * @title CrossTypes
 * @dev Library containing common types and utilities for cross-chain operations
 * This library provides:
 * - Data structures for cross-chain transactions
 * - Utility functions for address and token operations
 */
library CrossTypes {
    using SafeMath for uint;

    /**
     * @notice Main data structure for cross-chain operations
     * @dev Contains all necessary data and mappings for cross-chain functionality
     */
    struct Data {
        /**
         * @notice HTLC transaction data storage
         * @dev Stores information about Hash Time-Locked Contract transactions
         */
        HTLCTxLib.Data htlcTxData;

        /**
         * @notice Rapidity transaction data storage
         * @dev Stores information about rapid cross-chain transactions
         */
        RapidityTxLib.Data rapidityTxData;

        /**
         * @notice Quota management interface for storeman group
         * @dev Handles quota allocation and management for storeman groups
         */
        IQuota quota;

        /**
         * @notice Token management interface
         * @dev Handles token pair management and cross-chain token operations
         */
        ITokenManager tokenManager;

        /**
         * @notice Storeman group admin interface
         * @dev Manages storeman group administration and configuration
         */
        IStoremanGroup smgAdminProxy;

        /**
         * @notice Storeman group fee admin address
         * @dev Address responsible for managing storeman group fees
         */
        address smgFeeProxy;

        /**
         * @notice Signature verification interface
         * @dev Handles signature verification for cross-chain transactions
         */
        ISignatureVerifier sigVerifier;

        /**
         * @notice Mapping of storeman group fees
         * @dev Maps storeman group IDs to their respective fees
         */
        mapping(bytes32 => uint) mapStoremanFee;

        /**
         * @notice Mapping of contract fees between chains
         * @dev Maps source chain ID and destination chain ID to contract fees
         */
        mapping(uint => mapping(uint =>uint)) mapContractFee;

        /**
         * @notice Mapping of agent fees between chains
         * @dev Maps source chain ID and destination chain ID to agent fees
         */
        mapping(uint => mapping(uint =>uint)) mapAgentFee;
    }

    /**
     * @notice Converts bytes to address
     * @dev Uses assembly to efficiently convert bytes to address
     * @param b Bytes to convert
     * @return addr The converted address
     */
    function bytesToAddress(bytes memory b) internal pure returns (address addr) {
        assembly {
            addr := mload(add(b,20))
        }
    }

    /**
     * @notice Transfers tokens from the contract to a specified address
     * @dev Verifies the transfer was successful by checking balance changes
     * @param tokenScAddr Address of the token contract
     * @param to Address to receive the tokens
     * @param value Amount of tokens to transfer
     * @return bool True if transfer was successful
     * Requirements:
     * - Transfer must succeed
     * - Balance change must match the transfer amount
     */
    function transfer(address tokenScAddr, address to, uint value)
        internal
        returns(bool)
    {
        uint beforeBalance;
        uint afterBalance;
        IRC20Protocol token = IRC20Protocol(tokenScAddr);
        beforeBalance = token.balanceOf(to);
        (bool success,) = tokenScAddr.call(abi.encodeWithSelector(token.transfer.selector, to, value));
        require(success, "transfer failed");
        afterBalance = token.balanceOf(to);
        return afterBalance == beforeBalance.add(value);
    }

    /**
     * @notice Transfers tokens from one address to another
     * @dev Verifies the transfer was successful by checking balance changes
     * @param tokenScAddr Address of the token contract
     * @param from Address to transfer tokens from
     * @param to Address to receive the tokens
     * @param value Amount of tokens to transfer
     * @return bool True if transfer was successful
     * Requirements:
     * - Transfer must succeed
     * - Balance change must match the transfer amount
     */
    function transferFrom(address tokenScAddr, address from, address to, uint value)
        internal
        returns(bool)
    {
        uint beforeBalance;
        uint afterBalance;
        IRC20Protocol token = IRC20Protocol(tokenScAddr);
        beforeBalance = token.balanceOf(to);
        (bool success,) = tokenScAddr.call(abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
        require(success, "transferFrom failed");
        afterBalance = token.balanceOf(to);
        return afterBalance == beforeBalance.add(value);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.1;

/**
 * @title EtherTransfer
 * @dev Library for safe ether transfer operations
 * This library provides a safer alternative to Solidity's native transfer function
 * by allowing custom gas limits and better error handling
 */
library EtherTransfer {
    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2023/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount, uint256 gasLimit) internal {
        require(address(this).balance >= amount, "EtherTransfer: insufficient balance");

        (bool success, ) = recipient.call{value: amount, gas: gasLimit}("");
        require(success, "EtherTransfer: unable to send value, recipient may have reverted");
    }
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

/**
 * @title HTLCTxLib
 * @dev Library for managing Hash Time-Locked Contract (HTLC) transactions
 * This library provides functionality for:
 * - User and storeman transaction management
 * - Debt management between storeman groups
 * - Transaction status tracking and verification
 */
library HTLCTxLib {
    using SafeMath for uint;

    /**
     * @notice Enumeration of possible transaction statuses
     * @dev Status flow:
     * - None: Initial state
     * - Locked: Transaction is locked and pending
     * - Redeemed: Transaction has been completed
     * - Revoked: Transaction has been cancelled
     * - AssetLocked: Asset is locked in debt management
     * - DebtLocked: Debt is locked in debt management
     */
    enum TxStatus {None, Locked, Redeemed, Revoked, AssetLocked, DebtLocked}

    /**
     * @notice Parameters for user-initiated HTLC transactions
     * @dev Used when creating new user transactions
     * @param xHash Hash of the HTLC random number
     * @param smgID ID of the selected storeman group
     * @param tokenPairID ID of the token pair for cross-chain transfer
     * @param value Amount of tokens to transfer
     * @param lockFee Fee for the lock operation
     * @param lockedTime Duration for which the transaction is locked
     */
    struct HTLCUserParams {
        bytes32 xHash;
        bytes32 smgID;
        uint tokenPairID;
        uint value;
        uint lockFee;
        uint lockedTime;
    }

    /**
     * @notice Base structure for all HTLC transactions
     * @dev Contains common fields for all transaction types
     * @param smgID ID of the storeman group
     * @param lockedTime Duration for which the transaction is locked
     * @param beginLockedTime Timestamp when the transaction was locked
     * @param status Current status of the transaction
     */
    struct BaseTx {
        bytes32 smgID;
        uint lockedTime;
        uint beginLockedTime;
        TxStatus status;
    }

    /**
     * @notice Structure for user-initiated transactions
     * @dev Extends BaseTx with user-specific information
     * @param baseTx Base transaction information
     * @param tokenPairID ID of the token pair
     * @param value Amount of tokens
     * @param fee Transaction fee
     * @param userAccount Address of the user initiating the transaction
     */
    struct UserTx {
        BaseTx baseTx;
        uint tokenPairID;
        uint value;
        uint fee;
        address userAccount;
    }

    /**
     * @notice Structure for storeman-initiated transactions
     * @dev Extends BaseTx with storeman-specific information
     * @param baseTx Base transaction information
     * @param tokenPairID ID of the token pair
     * @param value Amount of tokens
     * @param userAccount Address of the user to receive tokens
     */
    struct SmgTx {
        BaseTx baseTx;
        uint tokenPairID;
        uint value;
        address userAccount;
    }

    /**
     * @notice Structure for storeman debt transactions
     * @dev Extends BaseTx with debt-specific information
     * @param baseTx Base transaction information
     * @param srcSmgID ID of the source storeman group
     */
    struct DebtTx {
        BaseTx baseTx;
        bytes32 srcSmgID;
    }

    /**
     * @notice Main data structure for HTLC transactions
     * @dev Contains mappings for all transaction types
     * @param mapHashXUserTxs Mapping of transaction hashes to user transactions
     * @param mapHashXSmgTxs Mapping of transaction hashes to storeman transactions
     * @param mapHashXDebtTxs Mapping of transaction hashes to debt transactions
     */
    struct Data {
        mapping(bytes32 => UserTx) mapHashXUserTxs;
        mapping(bytes32 => SmgTx) mapHashXSmgTxs;
        mapping(bytes32 => DebtTx) mapHashXDebtTxs;
    }

    /**
     * @notice Adds a new user transaction
     * @dev Creates a new user transaction with the provided parameters
     * @param self The storage data structure
     * @param params Parameters for the new transaction
     * Requirements:
     * - Transaction must not already exist
     */
    function addUserTx(Data storage self, HTLCUserParams memory params)
        public
    {
        UserTx memory userTx = self.mapHashXUserTxs[params.xHash];
        // UserTx storage userTx = self.mapHashXUserTxs[params.xHash];
        // require(params.value != 0, "Value is invalid");
        require(userTx.baseTx.status == TxStatus.None, "User tx exists");

        userTx.baseTx.smgID = params.smgID;
        userTx.baseTx.lockedTime = params.lockedTime;
        userTx.baseTx.beginLockedTime = block.timestamp;
        userTx.baseTx.status = TxStatus.Locked;
        userTx.tokenPairID = params.tokenPairID;
        userTx.value = params.value;
        userTx.fee = params.lockFee;
        userTx.userAccount = msg.sender;

        self.mapHashXUserTxs[params.xHash] = userTx;
    }

    /**
     * @notice Redeems a user transaction
     * @dev Used for storeman redeem (outbound) operations
     * @param self The storage data structure
     * @param x The HTLC random number
     * @return xHash The hash of the random number
     * Requirements:
     * - Transaction must be in Locked status
     * - Transaction must not be expired
     */
    function redeemUserTx(Data storage self, bytes32 x)
        external
        returns(bytes32 xHash)
    {
        xHash = sha256(abi.encodePacked(x));

        UserTx storage userTx = self.mapHashXUserTxs[xHash];
        require(userTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(block.timestamp < userTx.baseTx.beginLockedTime.add(userTx.baseTx.lockedTime), "Redeem timeout");

        userTx.baseTx.status = TxStatus.Redeemed;

        return xHash;
    }

    /**
     * @notice Revokes a user transaction
     * @dev Allows cancellation of expired transactions
     * @param self The storage data structure
     * @param xHash Hash of the HTLC random number
     * Requirements:
     * - Transaction must be in Locked status
     * - Transaction must be expired
     */
    function revokeUserTx(Data storage self, bytes32 xHash)
        external
    {
        UserTx storage userTx = self.mapHashXUserTxs[xHash];
        require(userTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(block.timestamp >= userTx.baseTx.beginLockedTime.add(userTx.baseTx.lockedTime), "Revoke is not permitted");

        userTx.baseTx.status = TxStatus.Revoked;
    }

    /**
     * @notice Retrieves user transaction information
     * @dev Returns all relevant information about a user transaction
     * @param self The storage data structure
     * @param xHash Hash of the HTLC random number
     * @return smgID ID of the storeman group
     * @return tokenPairID ID of the token pair
     * @return value Amount of tokens
     * @return fee Transaction fee
     * @return userAccount Address of the user
     */
    function getUserTx(Data storage self, bytes32 xHash)
        external
        view
        returns (bytes32, uint, uint, uint, address)
    {
        UserTx storage userTx = self.mapHashXUserTxs[xHash];
        return (userTx.baseTx.smgID, userTx.tokenPairID, userTx.value, userTx.fee, userTx.userAccount);
    }

    /**
     * @notice Adds a new storeman transaction
     * @dev Creates a new storeman transaction with the provided parameters
     * @param self The storage data structure
     * @param xHash Hash of the HTLC random number
     * @param smgID ID of the storeman group
     * @param tokenPairID ID of the token pair
     * @param value Amount of tokens
     * @param userAccount Address of the user to receive tokens
     * @param lockedTime Duration for which the transaction is locked
     * Requirements:
     * - Value must be non-zero
     * - Transaction must not already exist
     */
    function addSmgTx(Data storage self, bytes32 xHash, bytes32 smgID, uint tokenPairID, uint value, address userAccount, uint lockedTime)
        external
    {
        SmgTx memory smgTx = self.mapHashXSmgTxs[xHash];
        // SmgTx storage smgTx = self.mapHashXSmgTxs[xHash];
        require(value != 0, "Value is invalid");
        require(smgTx.baseTx.status == TxStatus.None, "Smg tx exists");

        smgTx.baseTx.smgID = smgID;
        smgTx.baseTx.status = TxStatus.Locked;
        smgTx.baseTx.lockedTime = lockedTime;
        smgTx.baseTx.beginLockedTime = block.timestamp;
        smgTx.tokenPairID = tokenPairID;
        smgTx.value = value;
        smgTx.userAccount = userAccount;

        self.mapHashXSmgTxs[xHash] = smgTx;
    }

    /**
     * @notice Redeems a storeman transaction
     * @dev Used for user redeem (inbound) operations
     * @param self The storage data structure
     * @param x The HTLC random number
     * @return xHash The hash of the random number
     * Requirements:
     * - Transaction must be in Locked status
     * - Transaction must not be expired
     */
    function redeemSmgTx(Data storage self, bytes32 x)
        external
        returns(bytes32 xHash)
    {
        xHash = sha256(abi.encodePacked(x));

        SmgTx storage smgTx = self.mapHashXSmgTxs[xHash];
        require(smgTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(block.timestamp < smgTx.baseTx.beginLockedTime.add(smgTx.baseTx.lockedTime), "Redeem timeout");

        smgTx.baseTx.status = TxStatus.Redeemed;

        return xHash;
    }

    /**
     * @notice Revokes a storeman transaction
     * @dev Allows cancellation of expired transactions
     * @param self The storage data structure
     * @param xHash Hash of the HTLC random number
     * Requirements:
     * - Transaction must be in Locked status
     * - Transaction must be expired
     */
    function revokeSmgTx(Data storage self, bytes32 xHash)
        external
    {
        SmgTx storage smgTx = self.mapHashXSmgTxs[xHash];
        require(smgTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(block.timestamp >= smgTx.baseTx.beginLockedTime.add(smgTx.baseTx.lockedTime), "Revoke is not permitted");

        smgTx.baseTx.status = TxStatus.Revoked;
    }

    /**
     * @notice Retrieves storeman transaction information
     * @dev Returns all relevant information about a storeman transaction
     * @param self The storage data structure
     * @param xHash Hash of the HTLC random number
     * @return smgID ID of the storeman group
     * @return tokenPairID ID of the token pair
     * @return value Amount of tokens
     * @return userAccount Address of the user to receive tokens
     */
    function getSmgTx(Data storage self, bytes32 xHash)
        external
        view
        returns (bytes32, uint, uint, address)
    {
        SmgTx storage smgTx = self.mapHashXSmgTxs[xHash];
        return (smgTx.baseTx.smgID, smgTx.tokenPairID, smgTx.value, smgTx.userAccount);
    }

    /**
     * @notice Adds a new debt transaction
     * @dev Creates a new debt transaction between storeman groups
     * @param self The storage data structure
     * @param xHash Hash of the HTLC random number
     * @param srcSmgID ID of the source storeman group
     * @param destSmgID ID of the destination storeman group
     * @param lockedTime Duration for which the transaction is locked
     * @param status Initial status of the transaction
     * Requirements:
     * - Transaction must not already exist
     * - Status must be either Locked or DebtLocked
     */
    function addDebtTx(Data storage self, bytes32 xHash, bytes32 srcSmgID, bytes32 destSmgID, uint lockedTime, TxStatus status)
        external
    {
        DebtTx memory debtTx = self.mapHashXDebtTxs[xHash];
        // DebtTx storage debtTx = self.mapHashXDebtTxs[xHash];
        require(debtTx.baseTx.status == TxStatus.None, "Debt tx exists");

        debtTx.baseTx.smgID = destSmgID;
        debtTx.baseTx.status = status;//TxStatus.Locked;
        debtTx.baseTx.lockedTime = lockedTime;
        debtTx.baseTx.beginLockedTime = block.timestamp;
        debtTx.srcSmgID = srcSmgID;

        self.mapHashXDebtTxs[xHash] = debtTx;
    }

    /**
     * @notice Redeems a debt transaction
     * @dev Used to complete debt transfer between storeman groups
     * @param self The storage data structure
     * @param x The HTLC random number
     * @return xHash The hash of the random number
     * Requirements:
     * - Transaction must be in Locked or DebtLocked status
     * - Transaction must not be expired
     */
    function redeemDebtTx(Data storage self, bytes32 x, TxStatus status)
        external
        returns(bytes32 xHash)
    {
        xHash = sha256(abi.encodePacked(x));

        DebtTx storage debtTx = self.mapHashXDebtTxs[xHash];
        // require(debtTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(debtTx.baseTx.status == status, "Status is not locked");
        require(block.timestamp < debtTx.baseTx.beginLockedTime.add(debtTx.baseTx.lockedTime), "Redeem timeout");

        debtTx.baseTx.status = TxStatus.Redeemed;

        return xHash;
    }

    /**
     * @notice Revokes a debt transaction
     * @dev Allows cancellation of expired debt transactions
     * @param self The storage data structure
     * @param xHash Hash of the HTLC random number
     * Requirements:
     * - Transaction must be in Locked or DebtLocked status
     * - Transaction must be expired
     */
    function revokeDebtTx(Data storage self, bytes32 xHash, TxStatus status)
        external
    {
        DebtTx storage debtTx = self.mapHashXDebtTxs[xHash];
        // require(debtTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(debtTx.baseTx.status == status, "Status is not locked");
        require(block.timestamp >= debtTx.baseTx.beginLockedTime.add(debtTx.baseTx.lockedTime), "Revoke is not permitted");

        debtTx.baseTx.status = TxStatus.Revoked;
    }

    /**
     * @notice Retrieves debt transaction information
     * @dev Returns all relevant information about a debt transaction
     * @param self The storage data structure
     * @param xHash Hash of the HTLC random number
     * @return smgID ID of the storeman group
     * @return srcSmgID ID of the source storeman group
     */
    function getDebtTx(Data storage self, bytes32 xHash)
        external
        view
        returns (bytes32, bytes32)
    {
        DebtTx storage debtTx = self.mapHashXDebtTxs[xHash];
        return (debtTx.srcSmgID, debtTx.baseTx.smgID);
    }

    function getLeftTime(uint endTime) private view returns (uint) {
        if (block.timestamp < endTime) {
            return endTime.sub(block.timestamp);
        }
        return 0;
    }

    /// @notice                     function for get debt info
    /// @param xHash                hash of HTLC random number
    /// @return leftTime            the left lock time
    function getLeftLockedTime(Data storage self, bytes32 xHash)
        external
        view
        returns (uint leftTime)
    {
        UserTx storage userTx = self.mapHashXUserTxs[xHash];
        if (userTx.baseTx.status != TxStatus.None) {
            return getLeftTime(userTx.baseTx.beginLockedTime.add(userTx.baseTx.lockedTime));
        }
        SmgTx storage smgTx = self.mapHashXSmgTxs[xHash];
        if (smgTx.baseTx.status != TxStatus.None) {
            return getLeftTime(smgTx.baseTx.beginLockedTime.add(smgTx.baseTx.lockedTime));
        }
        DebtTx storage debtTx = self.mapHashXDebtTxs[xHash];
        if (debtTx.baseTx.status != TxStatus.None) {
            return getLeftTime(debtTx.baseTx.beginLockedTime.add(debtTx.baseTx.lockedTime));
        }
        require(false, 'invalid xHash');
    }
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

/**
 * @title RapidityTxLib
 * @dev Library for managing rapid cross-chain transaction status
 * This library provides functionality for:
 * - Tracking transaction status
 * - Managing rapid cross-chain transactions
 */
library RapidityTxLib {

    /**
     * @notice Enumeration of possible transaction statuses
     * @dev Defines the states a rapidity transaction can be in
     * - None: Initial state, transaction not yet processed
     * - Redeemed: Transaction has been completed
     */
    enum TxStatus {None, Redeemed}

    /**
     * @notice Main data structure for rapidity transactions
     * @dev Contains mappings for tracking transaction statuses
     * @param mapTxStatus Mapping of transaction unique IDs to their status
     */
    struct Data {
        mapping(bytes32 => TxStatus) mapTxStatus;
    }

    /**
     * @notice Adds a new rapidity transaction
     * @dev Marks a transaction as redeemed when it is added
     * @param self The storage data structure
     * @param uniqueID Unique identifier for the rapidity transaction
     * Requirements:
     * - Transaction must not already exist
     */
    function addRapidityTx(Data storage self, bytes32 uniqueID)
        internal
    {
        TxStatus status = self.mapTxStatus[uniqueID];
        require(status == TxStatus.None, "Rapidity tx exists");
        self.mapTxStatus[uniqueID] = TxStatus.Redeemed;
    }
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

interface IQuota {
  function userLock(uint tokenId, bytes32 storemanGroupId, uint value) external;
  function userBurn(uint tokenId, bytes32 storemanGroupId, uint value) external;

  function smgRelease(uint tokenId, bytes32 storemanGroupId, uint value) external;
  function smgMint(uint tokenId, bytes32 storemanGroupId, uint value) external;

  function upgrade(bytes32 storemanGroupId) external;

  function transferAsset(bytes32 srcStoremanGroupId, bytes32 dstStoremanGroupId) external;
  function receiveDebt(bytes32 srcStoremanGroupId, bytes32 dstStoremanGroupId) external;

  function getUserMintQuota(uint tokenId, bytes32 storemanGroupId) external view returns (uint);
  function getSmgMintQuota(uint tokenId, bytes32 storemanGroupId) external view returns (uint);

  function getUserBurnQuota(uint tokenId, bytes32 storemanGroupId) external view returns (uint);
  function getSmgBurnQuota(uint tokenId, bytes32 storemanGroupId) external view returns (uint);

  function getAsset(uint tokenId, bytes32 storemanGroupId) external view returns (uint asset, uint asset_receivable, uint asset_payable);
  function getDebt(uint tokenId, bytes32 storemanGroupId) external view returns (uint debt, uint debt_receivable, uint debt_payable);

  function isDebtClean(bytes32 storemanGroupId) external view returns (bool);
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

interface IRC20Protocol {
    function transfer(address, uint) external returns (bool);
    function transferFrom(address, address, uint) external returns (bool);
    function balanceOf(address _owner) external view returns (uint);
}

File 9 of 11 : ISignatureVerifier.sol
// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

interface ISignatureVerifier {
  function verify(
        uint curveId,
        bytes32 signature,
        bytes32 groupKeyX,
        bytes32 groupKeyY,
        bytes32 randomPointX,
        bytes32 randomPointY,
        bytes32 message
    ) external returns (bool);
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

interface IStoremanGroup {
    function getSelectedSmNumber(bytes32 groupId) external view returns(uint number);
    function getStoremanGroupConfig(bytes32 id) external view returns(bytes32 groupId, uint8 status, uint deposit, uint chain1, uint chain2, uint curve1, uint curve2,  bytes memory gpk1, bytes memory gpk2, uint startTime, uint endTime);
    function getDeposit(bytes32 id) external view returns(uint);
    function getStoremanGroupStatus(bytes32 id) external view returns(uint8 status, uint startTime, uint endTime);
    function setGpk(bytes32 groupId, bytes memory gpk1, bytes memory gpk2) external;
    function setInvalidSm(bytes32 groupId, uint[] memory indexs, uint8[] memory slashTypes) external returns(bool isContinue);
    function getThresholdByGrpId(bytes32 groupId) external view returns (uint);
    function getSelectedSmInfo(bytes32 groupId, uint index) external view returns(address wkAddr, bytes memory PK, bytes memory enodeId);
    function recordSmSlash(address wk) external;
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

interface ITokenManager {
    function getTokenPairInfo(uint id) external view
      returns (uint origChainID, bytes memory tokenOrigAccount, uint shadowChainID, bytes memory tokenShadowAccount);

    function getTokenPairInfoSlim(uint id) external view
      returns (uint origChainID, bytes memory tokenOrigAccount, uint shadowChainID);

    function getAncestorInfo(uint id) external view
      returns (bytes memory account, string memory name, string memory symbol, uint8 decimals, uint chainId);

    function mintToken(address tokenAddress, address to, uint value) external;

    function burnToken(address tokenAddress, address from, uint value) external;

    function mapTokenPairType(uint tokenPairID) external view
      returns (uint8 tokenPairType);

    // erc1155
    function mintNFT(uint tokenCrossType, address tokenAddress, address to, uint[] calldata ids, uint[] calldata values, bytes calldata data) external;
    function burnNFT(uint tokenCrossType, address tokenAddress, address from, uint[] calldata ids, uint[] calldata values) external;
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"uniqueID","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"smgID","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"indexed":false,"internalType":"string[]","name":"keys","type":"string[]"},{"indexed":false,"internalType":"bytes[]","name":"values","type":"bytes[]"}],"name":"SmgMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"uniqueID","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"smgID","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAccount","type":"address"},{"indexed":false,"internalType":"address","name":"userAccount","type":"address"}],"name":"SmgMintLogger","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"uniqueID","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"smgID","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"indexed":false,"internalType":"string[]","name":"keys","type":"string[]"},{"indexed":false,"internalType":"bytes[]","name":"values","type":"bytes[]"}],"name":"SmgRelease","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"uniqueID","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"smgID","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAccount","type":"address"},{"indexed":false,"internalType":"address","name":"userAccount","type":"address"}],"name":"SmgReleaseLogger","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"smgID","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"indexed":true,"internalType":"address","name":"tokenAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"contractFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"userAccount","type":"bytes"}],"name":"UserBurnLogger","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"smgID","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"indexed":true,"internalType":"address","name":"tokenAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"contractFee","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"userAccount","type":"bytes"}],"name":"UserLockLogger","type":"event"}]

6121ad61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c80634d448a941461005b5780637d2f59c01461007d5780638fd59dc71461009d578063f0e53f54146100bd575b600080fd5b81801561006757600080fd5b5061007b610076366004611acc565b6100dd565b005b81801561008957600080fd5b5061007b610098366004611bf9565b6105ee565b8180156100a957600080fd5b5061007b6100b8366004611ce0565b6109b3565b8180156100c957600080fd5b5061007b6100d8366004611da7565b610d06565b80516100ed9060038401906111b0565b60c08101516001600160a01b031661013d576101168160e0015182606001518360a00151611234565b6080810151156101385761013881610100015182608001518360a00151611234565b6102aa565b600582015460408281015190516375d2e27d60e01b815260048101919091526000916001600160a01b0316906375d2e27d90602401602060405180830381865afa15801561018f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b39190611e4b565b905060ff8116156101df5760405162461bcd60e51b81526004016101d690611e8b565b60405180910390fd5b60808201511561024d576102018260c001518361010001518460800151611364565b61024d5760405162461bcd60e51b815260206004820152601960248201527f5472616e7366657220746f6b656e20666565206661696c65640000000000000060448201526064016101d6565b6102648260c001518360e001518460600151611364565b6102a85760405162461bcd60e51b8152602060048201526015602482015274151c985b9cd9995c881d1bdad95b8819985a5b1959605a1b60448201526064016101d6565b505b60408051600480825260a08201909252600091816020015b60608152602001906001900390816102c257505060408051600480825260a0820190925291925060009190602082015b60608152602001906001900390816102f25790505090506040518060400160405280600d81526020016c3b30b63ab29d3ab4b73a191a9b60991b8152508260008151811061034257610342611eb0565b6020026020010181905250826060015160405160200161036491815260200190565b6040516020818303038152906040528160008151811061038657610386611eb0565b602002602001018190525060405180604001604052806014815260200173746f6b656e4163636f756e743a6164647265737360601b815250826001815181106103d1576103d1611eb0565b60200260200101819052508260c001516040516020016103f19190611ec6565b6040516020818303038152906040528160018151811061041357610413611eb0565b602002602001018190525060405180604001604052806013815260200172757365724163636f756e743a6164647265737360681b8152508260028151811061045d5761045d611eb0565b60200260200101819052508260e0015160405160200161047d9190611ec6565b6040516020818303038152906040528160028151811061049f5761049f611eb0565b60200260200101819052506040518060400160405280600b81526020016a3332b29d3ab4b73a191a9b60a91b815250826003815181106104e1576104e1611eb0565b6020026020010181905250826080015160405160200161050391815260200190565b6040516020818303038152906040528160038151811061052557610525611eb0565b60200260200101819052508260400151836020015184600001517f9b6eb2cafadf787e6afa45af20d7b3e7cbfab81b468152083b29bf659874572f8585604051610570929190611f33565b60405180910390a48260400151836020015184600001517f74a78f7a58df75c2eb07666a6e572aa46ec8fe8f2cd090e41cfca63178dafa2f86606001518760c001518860e001516040516105e0939291909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a450505050565b60058201546020820151604051635c83993b60e11b815260048101919091526001600160a01b039091169060009081906060908190859063b907327690602401600060405180830381865afa15801561064b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106739190810190612038565b92965094509250905060008490036106c45760405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b60448201526064016101d6565b60a0860151606087015160009085900361073357816000036106ff576000858152600a8a016020908152604080832089845290915290205491505b81600003610726576000858152600a8a016020908152604080832083805290915290205491505b60148301515b90506107d3565b858860600151036107965781600003610765576000868152600a8a016020908152604080832088845290915290205491505b8160000361078c576000868152600a8a016020908152604080832083805290915290205491505b601484015161072c565b60405162461bcd60e51b815260206004820152601260248201527124b73b30b634b2103a37b5b2b7103830b4b960711b60448201526064016101d6565b806001600160a01b03168860e001516001600160a01b0316146108305760405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081d1bdad95b881858d8dbdd5b9d605a1b60448201526064016101d6565b60208801516040516375d2e27d60e01b815260048101919091526001600160a01b038816906375d2e27d90602401602060405180830381865afa15801561087b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089f9190611e4b565b60ff16955085156108c25760405162461bcd60e51b81526004016101d690611e8b565b6108d28782338b6040015161153d565b61090c5760405162461bcd60e51b815260206004820152600b60248201526a109d5c9b8819985a5b195960aa1b60448201526064016101d6565b811561092657610926886101200151838a60c00151611234565b6000610932348461169e565b905080156109495761094933828b60c00151611234565b816001600160a01b031689602001518a600001517fe314e23175856b9484e39ab0547753cf1b5cd0cbe3b0d7018c953d31f23fc7678c60400151878e608001518f610100015160405161099f94939291906120af565b60405180910390a450505050505050505050565b60058201546020820151604051635c83993b60e11b815260048101919091526001600160a01b039091169060009081906060908190859063b907327690602401600060405180830381865afa158015610a10573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a389190810190612038565b9296509450925090506000849003610a895760405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b60448201526064016101d6565b60808601516060870151600090869003610af85781600003610ac4576000868152600a8a016020908152604080832088845290915290205491505b81600003610aeb576000868152600a8a016020908152604080832083805290915290205491505b60148401515b9050610b5b565b848860600151036107965781600003610b2a576000858152600a8a016020908152604080832089845290915290205491505b81600003610b51576000858152600a8a016020908152604080832083805290915290205491505b6014830151610af1565b8115610b7457610b748860e00151838a60a00151611234565b60006001600160a01b038216610bac57610ba583610b9f8b604001513461169e90919063ffffffff16565b9061169e565b9050610ca2565b610bb6348461169e565b90506000886001600160a01b03166375d2e27d8b602001516040518263ffffffff1660e01b8152600401610bec91815260200190565b602060405180830381865afa158015610c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2d9190611e4b565b905060ff811615610c505760405162461bcd60e51b81526004016101d690611e8b565b610c608333308d604001516116b3565b610ca05760405162461bcd60e51b8152602060048201526011602482015270131bd8dac81d1bdad95b8819985a5b1959607a1b60448201526064016101d6565b505b8015610cb757610cb733828b60a00151611234565b816001600160a01b031689602001518a600001517f43eb196c5950c738b34cd1760941e0876559e4fb835498fe19016bc039ad61a98c60400151878e60c0015160405161099f939291906120de565b8051610d169060038401906111b0565b600582015460408083015190516375d2e27d60e01b81526001600160a01b039092169160009183916375d2e27d91610d549160040190815260200190565b602060405180830381865afa158015610d71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d959190611e4b565b905060ff811615610db85760405162461bcd60e51b81526004016101d690611e8b565b608083015115610e1857610dda828460a001518560e001518660800151611899565b610e185760405162461bcd60e51b815260206004820152600f60248201526e135a5b9d081999594819985a5b1959608a1b60448201526064016101d6565b610e30828460a001518560c001518660600151611899565b610e6a5760405162461bcd60e51b815260206004820152600b60248201526a135a5b9d0819985a5b195960aa1b60448201526064016101d6565b60408051600480825260a08201909252600091816020015b6060815260200190600190039081610e8257505060408051600480825260a0820190925291925060009190602082015b6060815260200190600190039081610eb25790505090506040518060400160405280600d81526020016c3b30b63ab29d3ab4b73a191a9b60991b81525082600081518110610f0257610f02611eb0565b60200260200101819052508460600151604051602001610f2491815260200190565b60405160208183030381529060405281600081518110610f4657610f46611eb0565b602002602001018190525060405180604001604052806014815260200173746f6b656e4163636f756e743a6164647265737360601b81525082600181518110610f9157610f91611eb0565b60200260200101819052508460a00151604051602001610fb19190611ec6565b60405160208183030381529060405281600181518110610fd357610fd3611eb0565b602002602001018190525060405180604001604052806013815260200172757365724163636f756e743a6164647265737360681b8152508260028151811061101d5761101d611eb0565b60200260200101819052508460c0015160405160200161103d9190611ec6565b6040516020818303038152906040528160028151811061105f5761105f611eb0565b60200260200101819052506040518060400160405280600b81526020016a3332b29d3ab4b73a191a9b60a91b815250826003815181106110a1576110a1611eb0565b602002602001018190525084608001516040516020016110c391815260200190565b604051602081830303815290604052816003815181106110e5576110e5611eb0565b60200260200101819052508460400151856020015186600001517fcfa91e1b502283be81bcd35b1d709a0d87a2045d6230837e2396892cf81411d98585604051611130929190611f33565b60405180910390a48460400151856020015186600001517f4419a30cc235fa47055246d53f2629b5687ca327b92dcde015fcebe0cc17ffab88606001518960a001518a60c001516040516111a0939291909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a4505050505050565b60008181526020839052604081205460ff16908160018111156111d5576111d5611e75565b146112175760405162461bcd60e51b815260206004820152601260248201527152617069646974792074782065786973747360701b60448201526064016101d6565b50600090815260209190915260409020805460ff19166001179055565b814710156112905760405162461bcd60e51b815260206004820152602360248201527f45746865725472616e736665723a20696e73756666696369656e742062616c616044820152626e636560e81b60648201526084016101d6565b6000836001600160a01b0316838390604051600060405180830381858888f193505050503d80600081146112e0576040519150601f19603f3d011682016040523d82523d6000602084013e6112e5565b606091505b505090508061135e576040805162461bcd60e51b81526020600482015260248101919091527f45746865725472616e736665723a20756e61626c6520746f2073656e6420766160448201527f6c75652c20726563697069656e74206d6179206861766520726576657274656460648201526084016101d6565b50505050565b6040516370a0823160e01b81526001600160a01b0383811660048301526000918291829187918216906370a0823190602401602060405180830381865afa1580156113b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d79190612106565b604080516001600160a01b03898116602483015260448083018a905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151929550600092918a1691611434919061211f565b6000604051808303816000865af19150503d8060008114611471576040519150601f19603f3d011682016040523d82523d6000602084013e611476565b606091505b50509050806114b95760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d6565b6040516370a0823160e01b81526001600160a01b0388811660048301528316906370a0823190602401602060405180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115239190612106565b925061152f84876119eb565b909214979650505050505050565b6040516370a0823160e01b81526001600160a01b03838116600483015260009182918291908716906370a0823190602401602060405180830381865afa15801561158b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115af9190612106565b604051633416794d60e01b81526001600160a01b03888116600483015287811660248301526044820187905291935090881690633416794d90606401600060405180830381600087803b15801561160557600080fd5b505af1158015611619573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b038881166004830152891692506370a082319150602401602060405180830381865afa158015611663573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116879190612106565b9050611693828561169e565b149695505050505050565b60006116aa8284612151565b90505b92915050565b6040516370a0823160e01b81526001600160a01b0383811660048301526000918291829188918216906370a0823190602401602060405180830381865afa158015611702573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117269190612106565b604080516001600160a01b038a81166024830152898116604483015260648083018a905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151929550600092918b169161178b919061211f565b6000604051808303816000865af19150503d80600081146117c8576040519150601f19603f3d011682016040523d82523d6000602084013e6117cd565b606091505b50509050806118145760405162461bcd60e51b81526020600482015260136024820152721d1c985b9cd9995c919c9bdb4819985a5b1959606a1b60448201526064016101d6565b6040516370a0823160e01b81526001600160a01b0388811660048301528316906370a0823190602401602060405180830381865afa15801561185a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187e9190612106565b925061188a84876119eb565b90921498975050505050505050565b6040516370a0823160e01b81526001600160a01b03838116600483015260009182918291908716906370a0823190602401602060405180830381865afa1580156118e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190b9190612106565b6040516335f6196d60e11b81526001600160a01b03888116600483015287811660248301526044820187905291935090881690636bec32da90606401600060405180830381600087803b15801561196157600080fd5b505af1158015611975573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b038881166004830152891692506370a082319150602401602060405180830381865afa1580156119bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e39190612106565b905061169382855b60006116aa8284612164565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611a3157611a316119f7565b60405290565b604051610140810167ffffffffffffffff81118282101715611a3157611a316119f7565b604051610100810167ffffffffffffffff81118282101715611a3157611a316119f7565b604051601f8201601f1916810167ffffffffffffffff81118282101715611aa857611aa86119f7565b604052919050565b80356001600160a01b0381168114611ac757600080fd5b919050565b600080828403610140811215611ae157600080fd5b8335925061012080601f1983011215611af957600080fd5b611b01611a0d565b91506020850135825260408501356020830152606085013560408301526080850135606083015260a0850135608083015260c085013560a0830152611b4860e08601611ab0565b60c0830152610100611b5b818701611ab0565b60e0840152611b6b828701611ab0565b9083015250919491935090915050565b600067ffffffffffffffff821115611b9557611b956119f7565b50601f01601f191660200190565b600082601f830112611bb457600080fd5b8135611bc7611bc282611b7b565b611a7f565b818152846020838601011115611bdc57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215611c0c57600080fd5b82359150602083013567ffffffffffffffff80821115611c2b57600080fd5b908401906101408287031215611c4057600080fd5b611c48611a37565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c0820152611c9460e08401611ab0565b60e08201526101008084013583811115611cad57600080fd5b611cb989828701611ba3565b8284015250506101209150611ccf828401611ab0565b828201528093505050509250929050565b60008060408385031215611cf357600080fd5b82359150602083013567ffffffffffffffff80821115611d1257600080fd5b908401906101008287031215611d2757600080fd5b611d2f611a5b565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013582811115611d7757600080fd5b611d8388828601611ba3565b60c083015250611d9560e08401611ab0565b60e08201528093505050509250929050565b600080828403610120811215611dbc57600080fd5b8335925061010080601f1983011215611dd457600080fd5b611ddc611a5b565b91506020850135825260408501356020830152606085013560408301526080850135606083015260a08501356080830152611e1960c08601611ab0565b60a0830152611e2a60e08601611ab0565b60c0830152611e3a818601611ab0565b60e083015250809150509250929050565b600060208284031215611e5d57600080fd5b815160ff81168114611e6e57600080fd5b9392505050565b634e487b7160e01b600052602160045260246000fd5b6020808252600b908201526a139bdd081cdd5c1c1bdc9d60aa1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60609190911b6bffffffffffffffffffffffff1916815260140190565b60005b83811015611efe578181015183820152602001611ee6565b50506000910152565b60008151808452611f1f816020860160208601611ee3565b601f01601f19169290920160200192915050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611f8a57605f19888703018552611f78868351611f07565b95509382019390820190600101611f5c565b505085840381870152865180855281850193509150600582901b8401810187820160005b84811015611fdc57601f19878403018652611fca838351611f07565b95840195925090830190600101611fae565b50909998505050505050505050565b600082601f830112611ffc57600080fd5b815161200a611bc282611b7b565b81815284602083860101111561201f57600080fd5b612030826020830160208701611ee3565b949350505050565b6000806000806080858703121561204e57600080fd5b84519350602085015167ffffffffffffffff8082111561206d57600080fd5b61207988838901611feb565b945060408701519350606087015191508082111561209657600080fd5b506120a387828801611feb565b91505092959194509250565b8481528360208201528260408201526080606082015260006120d46080830184611f07565b9695505050505050565b8381528260208201526060604082015260006120fd6060830184611f07565b95945050505050565b60006020828403121561211857600080fd5b5051919050565b60008251612131818460208701611ee3565b9190910192915050565b634e487b7160e01b600052601160045260246000fd5b818103818111156116ad576116ad61213b565b808201808211156116ad576116ad61213b56fea2646970667358221220ff8ba02270f965e33fcd9a4fa9c07ecc22cba8bacab0b1c855d4b4a6c3b5f71a64736f6c63430008120033

Deployed Bytecode

0x7335b90f99680c426bf6753a78c364b045115cb46e30146080604052600436106100565760003560e01c80634d448a941461005b5780637d2f59c01461007d5780638fd59dc71461009d578063f0e53f54146100bd575b600080fd5b81801561006757600080fd5b5061007b610076366004611acc565b6100dd565b005b81801561008957600080fd5b5061007b610098366004611bf9565b6105ee565b8180156100a957600080fd5b5061007b6100b8366004611ce0565b6109b3565b8180156100c957600080fd5b5061007b6100d8366004611da7565b610d06565b80516100ed9060038401906111b0565b60c08101516001600160a01b031661013d576101168160e0015182606001518360a00151611234565b6080810151156101385761013881610100015182608001518360a00151611234565b6102aa565b600582015460408281015190516375d2e27d60e01b815260048101919091526000916001600160a01b0316906375d2e27d90602401602060405180830381865afa15801561018f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b39190611e4b565b905060ff8116156101df5760405162461bcd60e51b81526004016101d690611e8b565b60405180910390fd5b60808201511561024d576102018260c001518361010001518460800151611364565b61024d5760405162461bcd60e51b815260206004820152601960248201527f5472616e7366657220746f6b656e20666565206661696c65640000000000000060448201526064016101d6565b6102648260c001518360e001518460600151611364565b6102a85760405162461bcd60e51b8152602060048201526015602482015274151c985b9cd9995c881d1bdad95b8819985a5b1959605a1b60448201526064016101d6565b505b60408051600480825260a08201909252600091816020015b60608152602001906001900390816102c257505060408051600480825260a0820190925291925060009190602082015b60608152602001906001900390816102f25790505090506040518060400160405280600d81526020016c3b30b63ab29d3ab4b73a191a9b60991b8152508260008151811061034257610342611eb0565b6020026020010181905250826060015160405160200161036491815260200190565b6040516020818303038152906040528160008151811061038657610386611eb0565b602002602001018190525060405180604001604052806014815260200173746f6b656e4163636f756e743a6164647265737360601b815250826001815181106103d1576103d1611eb0565b60200260200101819052508260c001516040516020016103f19190611ec6565b6040516020818303038152906040528160018151811061041357610413611eb0565b602002602001018190525060405180604001604052806013815260200172757365724163636f756e743a6164647265737360681b8152508260028151811061045d5761045d611eb0565b60200260200101819052508260e0015160405160200161047d9190611ec6565b6040516020818303038152906040528160028151811061049f5761049f611eb0565b60200260200101819052506040518060400160405280600b81526020016a3332b29d3ab4b73a191a9b60a91b815250826003815181106104e1576104e1611eb0565b6020026020010181905250826080015160405160200161050391815260200190565b6040516020818303038152906040528160038151811061052557610525611eb0565b60200260200101819052508260400151836020015184600001517f9b6eb2cafadf787e6afa45af20d7b3e7cbfab81b468152083b29bf659874572f8585604051610570929190611f33565b60405180910390a48260400151836020015184600001517f74a78f7a58df75c2eb07666a6e572aa46ec8fe8f2cd090e41cfca63178dafa2f86606001518760c001518860e001516040516105e0939291909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a450505050565b60058201546020820151604051635c83993b60e11b815260048101919091526001600160a01b039091169060009081906060908190859063b907327690602401600060405180830381865afa15801561064b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106739190810190612038565b92965094509250905060008490036106c45760405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b60448201526064016101d6565b60a0860151606087015160009085900361073357816000036106ff576000858152600a8a016020908152604080832089845290915290205491505b81600003610726576000858152600a8a016020908152604080832083805290915290205491505b60148301515b90506107d3565b858860600151036107965781600003610765576000868152600a8a016020908152604080832088845290915290205491505b8160000361078c576000868152600a8a016020908152604080832083805290915290205491505b601484015161072c565b60405162461bcd60e51b815260206004820152601260248201527124b73b30b634b2103a37b5b2b7103830b4b960711b60448201526064016101d6565b806001600160a01b03168860e001516001600160a01b0316146108305760405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081d1bdad95b881858d8dbdd5b9d605a1b60448201526064016101d6565b60208801516040516375d2e27d60e01b815260048101919091526001600160a01b038816906375d2e27d90602401602060405180830381865afa15801561087b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089f9190611e4b565b60ff16955085156108c25760405162461bcd60e51b81526004016101d690611e8b565b6108d28782338b6040015161153d565b61090c5760405162461bcd60e51b815260206004820152600b60248201526a109d5c9b8819985a5b195960aa1b60448201526064016101d6565b811561092657610926886101200151838a60c00151611234565b6000610932348461169e565b905080156109495761094933828b60c00151611234565b816001600160a01b031689602001518a600001517fe314e23175856b9484e39ab0547753cf1b5cd0cbe3b0d7018c953d31f23fc7678c60400151878e608001518f610100015160405161099f94939291906120af565b60405180910390a450505050505050505050565b60058201546020820151604051635c83993b60e11b815260048101919091526001600160a01b039091169060009081906060908190859063b907327690602401600060405180830381865afa158015610a10573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a389190810190612038565b9296509450925090506000849003610a895760405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b60448201526064016101d6565b60808601516060870151600090869003610af85781600003610ac4576000868152600a8a016020908152604080832088845290915290205491505b81600003610aeb576000868152600a8a016020908152604080832083805290915290205491505b60148401515b9050610b5b565b848860600151036107965781600003610b2a576000858152600a8a016020908152604080832089845290915290205491505b81600003610b51576000858152600a8a016020908152604080832083805290915290205491505b6014830151610af1565b8115610b7457610b748860e00151838a60a00151611234565b60006001600160a01b038216610bac57610ba583610b9f8b604001513461169e90919063ffffffff16565b9061169e565b9050610ca2565b610bb6348461169e565b90506000886001600160a01b03166375d2e27d8b602001516040518263ffffffff1660e01b8152600401610bec91815260200190565b602060405180830381865afa158015610c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2d9190611e4b565b905060ff811615610c505760405162461bcd60e51b81526004016101d690611e8b565b610c608333308d604001516116b3565b610ca05760405162461bcd60e51b8152602060048201526011602482015270131bd8dac81d1bdad95b8819985a5b1959607a1b60448201526064016101d6565b505b8015610cb757610cb733828b60a00151611234565b816001600160a01b031689602001518a600001517f43eb196c5950c738b34cd1760941e0876559e4fb835498fe19016bc039ad61a98c60400151878e60c0015160405161099f939291906120de565b8051610d169060038401906111b0565b600582015460408083015190516375d2e27d60e01b81526001600160a01b039092169160009183916375d2e27d91610d549160040190815260200190565b602060405180830381865afa158015610d71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d959190611e4b565b905060ff811615610db85760405162461bcd60e51b81526004016101d690611e8b565b608083015115610e1857610dda828460a001518560e001518660800151611899565b610e185760405162461bcd60e51b815260206004820152600f60248201526e135a5b9d081999594819985a5b1959608a1b60448201526064016101d6565b610e30828460a001518560c001518660600151611899565b610e6a5760405162461bcd60e51b815260206004820152600b60248201526a135a5b9d0819985a5b195960aa1b60448201526064016101d6565b60408051600480825260a08201909252600091816020015b6060815260200190600190039081610e8257505060408051600480825260a0820190925291925060009190602082015b6060815260200190600190039081610eb25790505090506040518060400160405280600d81526020016c3b30b63ab29d3ab4b73a191a9b60991b81525082600081518110610f0257610f02611eb0565b60200260200101819052508460600151604051602001610f2491815260200190565b60405160208183030381529060405281600081518110610f4657610f46611eb0565b602002602001018190525060405180604001604052806014815260200173746f6b656e4163636f756e743a6164647265737360601b81525082600181518110610f9157610f91611eb0565b60200260200101819052508460a00151604051602001610fb19190611ec6565b60405160208183030381529060405281600181518110610fd357610fd3611eb0565b602002602001018190525060405180604001604052806013815260200172757365724163636f756e743a6164647265737360681b8152508260028151811061101d5761101d611eb0565b60200260200101819052508460c0015160405160200161103d9190611ec6565b6040516020818303038152906040528160028151811061105f5761105f611eb0565b60200260200101819052506040518060400160405280600b81526020016a3332b29d3ab4b73a191a9b60a91b815250826003815181106110a1576110a1611eb0565b602002602001018190525084608001516040516020016110c391815260200190565b604051602081830303815290604052816003815181106110e5576110e5611eb0565b60200260200101819052508460400151856020015186600001517fcfa91e1b502283be81bcd35b1d709a0d87a2045d6230837e2396892cf81411d98585604051611130929190611f33565b60405180910390a48460400151856020015186600001517f4419a30cc235fa47055246d53f2629b5687ca327b92dcde015fcebe0cc17ffab88606001518960a001518a60c001516040516111a0939291909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a4505050505050565b60008181526020839052604081205460ff16908160018111156111d5576111d5611e75565b146112175760405162461bcd60e51b815260206004820152601260248201527152617069646974792074782065786973747360701b60448201526064016101d6565b50600090815260209190915260409020805460ff19166001179055565b814710156112905760405162461bcd60e51b815260206004820152602360248201527f45746865725472616e736665723a20696e73756666696369656e742062616c616044820152626e636560e81b60648201526084016101d6565b6000836001600160a01b0316838390604051600060405180830381858888f193505050503d80600081146112e0576040519150601f19603f3d011682016040523d82523d6000602084013e6112e5565b606091505b505090508061135e576040805162461bcd60e51b81526020600482015260248101919091527f45746865725472616e736665723a20756e61626c6520746f2073656e6420766160448201527f6c75652c20726563697069656e74206d6179206861766520726576657274656460648201526084016101d6565b50505050565b6040516370a0823160e01b81526001600160a01b0383811660048301526000918291829187918216906370a0823190602401602060405180830381865afa1580156113b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d79190612106565b604080516001600160a01b03898116602483015260448083018a905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151929550600092918a1691611434919061211f565b6000604051808303816000865af19150503d8060008114611471576040519150601f19603f3d011682016040523d82523d6000602084013e611476565b606091505b50509050806114b95760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d6565b6040516370a0823160e01b81526001600160a01b0388811660048301528316906370a0823190602401602060405180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115239190612106565b925061152f84876119eb565b909214979650505050505050565b6040516370a0823160e01b81526001600160a01b03838116600483015260009182918291908716906370a0823190602401602060405180830381865afa15801561158b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115af9190612106565b604051633416794d60e01b81526001600160a01b03888116600483015287811660248301526044820187905291935090881690633416794d90606401600060405180830381600087803b15801561160557600080fd5b505af1158015611619573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b038881166004830152891692506370a082319150602401602060405180830381865afa158015611663573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116879190612106565b9050611693828561169e565b149695505050505050565b60006116aa8284612151565b90505b92915050565b6040516370a0823160e01b81526001600160a01b0383811660048301526000918291829188918216906370a0823190602401602060405180830381865afa158015611702573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117269190612106565b604080516001600160a01b038a81166024830152898116604483015260648083018a905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151929550600092918b169161178b919061211f565b6000604051808303816000865af19150503d80600081146117c8576040519150601f19603f3d011682016040523d82523d6000602084013e6117cd565b606091505b50509050806118145760405162461bcd60e51b81526020600482015260136024820152721d1c985b9cd9995c919c9bdb4819985a5b1959606a1b60448201526064016101d6565b6040516370a0823160e01b81526001600160a01b0388811660048301528316906370a0823190602401602060405180830381865afa15801561185a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187e9190612106565b925061188a84876119eb565b90921498975050505050505050565b6040516370a0823160e01b81526001600160a01b03838116600483015260009182918291908716906370a0823190602401602060405180830381865afa1580156118e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190b9190612106565b6040516335f6196d60e11b81526001600160a01b03888116600483015287811660248301526044820187905291935090881690636bec32da90606401600060405180830381600087803b15801561196157600080fd5b505af1158015611975573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b038881166004830152891692506370a082319150602401602060405180830381865afa1580156119bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e39190612106565b905061169382855b60006116aa8284612164565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611a3157611a316119f7565b60405290565b604051610140810167ffffffffffffffff81118282101715611a3157611a316119f7565b604051610100810167ffffffffffffffff81118282101715611a3157611a316119f7565b604051601f8201601f1916810167ffffffffffffffff81118282101715611aa857611aa86119f7565b604052919050565b80356001600160a01b0381168114611ac757600080fd5b919050565b600080828403610140811215611ae157600080fd5b8335925061012080601f1983011215611af957600080fd5b611b01611a0d565b91506020850135825260408501356020830152606085013560408301526080850135606083015260a0850135608083015260c085013560a0830152611b4860e08601611ab0565b60c0830152610100611b5b818701611ab0565b60e0840152611b6b828701611ab0565b9083015250919491935090915050565b600067ffffffffffffffff821115611b9557611b956119f7565b50601f01601f191660200190565b600082601f830112611bb457600080fd5b8135611bc7611bc282611b7b565b611a7f565b818152846020838601011115611bdc57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215611c0c57600080fd5b82359150602083013567ffffffffffffffff80821115611c2b57600080fd5b908401906101408287031215611c4057600080fd5b611c48611a37565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c0820152611c9460e08401611ab0565b60e08201526101008084013583811115611cad57600080fd5b611cb989828701611ba3565b8284015250506101209150611ccf828401611ab0565b828201528093505050509250929050565b60008060408385031215611cf357600080fd5b82359150602083013567ffffffffffffffff80821115611d1257600080fd5b908401906101008287031215611d2757600080fd5b611d2f611a5b565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013582811115611d7757600080fd5b611d8388828601611ba3565b60c083015250611d9560e08401611ab0565b60e08201528093505050509250929050565b600080828403610120811215611dbc57600080fd5b8335925061010080601f1983011215611dd457600080fd5b611ddc611a5b565b91506020850135825260408501356020830152606085013560408301526080850135606083015260a08501356080830152611e1960c08601611ab0565b60a0830152611e2a60e08601611ab0565b60c0830152611e3a818601611ab0565b60e083015250809150509250929050565b600060208284031215611e5d57600080fd5b815160ff81168114611e6e57600080fd5b9392505050565b634e487b7160e01b600052602160045260246000fd5b6020808252600b908201526a139bdd081cdd5c1c1bdc9d60aa1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60609190911b6bffffffffffffffffffffffff1916815260140190565b60005b83811015611efe578181015183820152602001611ee6565b50506000910152565b60008151808452611f1f816020860160208601611ee3565b601f01601f19169290920160200192915050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611f8a57605f19888703018552611f78868351611f07565b95509382019390820190600101611f5c565b505085840381870152865180855281850193509150600582901b8401810187820160005b84811015611fdc57601f19878403018652611fca838351611f07565b95840195925090830190600101611fae565b50909998505050505050505050565b600082601f830112611ffc57600080fd5b815161200a611bc282611b7b565b81815284602083860101111561201f57600080fd5b612030826020830160208701611ee3565b949350505050565b6000806000806080858703121561204e57600080fd5b84519350602085015167ffffffffffffffff8082111561206d57600080fd5b61207988838901611feb565b945060408701519350606087015191508082111561209657600080fd5b506120a387828801611feb565b91505092959194509250565b8481528360208201528260408201526080606082015260006120d46080830184611f07565b9695505050505050565b8381528260208201526060604082015260006120fd6060830184611f07565b95945050505050565b60006020828403121561211857600080fd5b5051919050565b60008251612131818460208701611ee3565b9190910192915050565b634e487b7160e01b600052601160045260246000fd5b818103818111156116ad576116ad61213b565b808201808211156116ad576116ad61213b56fea2646970667358221220ff8ba02270f965e33fcd9a4fa9c07ecc22cba8bacab0b1c855d4b4a6c3b5f71a64736f6c63430008120033

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
0x35B90F99680C426bf6753a78C364B045115cb46e
Loading...
Loading
Loading...
Loading

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.