Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
CrossDelegateV6
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 "./CrossDelegateV5.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
/**
* @title CrossDelegateV6
* @dev Enhanced version of CrossDelegateV6 that adds minimum cross-chain asset amount functionality
* This contract extends CrossDelegateV5
*/
contract CrossDelegateV6 is CrossDelegateV5 {
using EnumerableMap for EnumerableMap.UintToUintMap;
/** STRUCT **/
struct SetMinTokenPairCrossChainAmountParam {
uint256 tokenPairID;
uint256 minAmount;
}
/**
* @dev Uses an EnumerableMap to store token pair IDs (uint256) mapped to their minimum cross-chain amounts (uint256).
* This structure allows for efficient iteration over pairs (via .length() and .at(index)) and safe lookups (via .tryGet(key)).
* Internal visibility ensures it's only accessible within the contract or derived contracts.
* Emits events on set() operations if configured in the library.
*/
EnumerableMap.UintToUintMap internal minTokenPairCrossChainAmount; // key: tokenPairID, value: min amount
/** MODIFIERS **/
/**
* @notice Ensures the caller has admin privileges
* @dev Checks if the caller is an admin, the main admin, or the owner
*/
modifier checkCrossChainAmount(uint256 tokenPairID, uint256 crossChainAmount) {
uint256 minAmount = getMinTokenPairCrossChainAmount(tokenPairID);
require(crossChainAmount >= minAmount, "CrossDelegateV6: Amount below minimum");
_;
}
/** EVENTS **/
/**
* @notice Emitted when a new minimum cross-chain asset value is set
* @param tokenPairID ID of the token pair
* @param minAmount The minimum cross-chain asset value
*/
event SetMinTokenPairCrossChainAmount(uint256 tokenPairID, uint256 minAmount);
/**
*
* MANIPULATIONS
*
*/
/**
* @notice Initiates a cross-chain token transfer by locking original tokens
* @dev This function handles the initial step of cross-chain transfer where original tokens are locked
* @param smgID ID of the storeman group handling the transfer
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param value Amount of tokens to transfer
* @param userAccount Account information for receiving tokens on the destination chain
* Requirements:
* - Contract must not be halted
* - Storeman group must be ready
* - Value must be greater than the minimum value
* - Token pair must exist
*/
function userLock(bytes32 smgID, uint tokenPairID, uint value, bytes calldata userAccount)
public
payable
override
checkCrossChainAmount(tokenPairID, value)
{
super.userLock(smgID, tokenPairID, value, userAccount);
}
/**
* @notice Initiates a cross-chain token transfer by burning WRC20 tokens
* @dev This function handles the initial step of cross-chain transfer where WRC20 tokens are burned
* @param smgID ID of the storeman group handling the transfer
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param value Amount of tokens to transfer
* @param fee Fee for the transfer operation
* @param tokenAccount Address of the token contract
* @param userAccount Account information for receiving tokens on the destination chain
* Requirements:
* - Contract must not be halted
* - Storeman group must be ready
* - Value must be greater than fee
* - Token pair must exist
* - Value must be greater than the minimum value
*/
function userBurn(bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, bytes calldata userAccount)
public
payable
override
checkCrossChainAmount(tokenPairID, value)
{
super.userBurn(smgID, tokenPairID, value, fee, tokenAccount, userAccount);
}
/**
* @notice Sets the minimum cross-chain transfer amounts for multiple token pairs.
* @dev This function updates the minimum required amount for each token pair in the params array.
* It iterates over the array and sets the value in the storage mapping.
* Emits events for each update if configured in the storage structure.
* @param params Array of SetMinTokenPairCrossChainAmountParam structs containing tokenPairID and minAmount.
* @custom:requires Only callable by the operator (via onlyOperator modifier).
*/
function setMinTokenPairCrossChainAmount(SetMinTokenPairCrossChainAmountParam[] calldata params) external virtual onlyOperator {
for (uint256 i = 0; i < params.length; i++) {
if (params[i].minAmount > 0) {
minTokenPairCrossChainAmount.set(params[i].tokenPairID, params[i].minAmount);
} else {
minTokenPairCrossChainAmount.remove(params[i].tokenPairID);
}
emit SetMinTokenPairCrossChainAmount(params[i].tokenPairID, params[i].minAmount);
}
}
/**
* @notice Retrieves the total number of token pairs with configured minimum cross-chain amounts.
* @dev Returns the length of the storage structure holding the token pair minimums.
* Useful for pagination or checking the size of the configuration.
* @return length The number of entries in the minTokenPairCrossChainAmount storage.
*/
function getMinTokenPairCrossChainAmountLength() public view virtual returns (uint256 length) {
length = minTokenPairCrossChainAmount.length();
}
/**
* @notice Retrieves the minimum cross-chain amount for a token pair by its index in the storage.
* @dev Fetches the tokenPairID and minAmount at the specified index.
* Ensures the index is within bounds to prevent out-of-range errors.
* @param index The index in the storage array/map.
* @return tokenPairID The token pair ID at the given index.
* @return minAmount The minimum cross-chain amount for that token pair.
* @custom:requires Index must be less than the total length (reverts otherwise).
*/
function getMinTokenPairCrossChainAmountByIndex(uint256 index) public view virtual returns (uint256 tokenPairID, uint256 minAmount) {
uint256 length = getMinTokenPairCrossChainAmountLength();
require(index < length, "Index out of bounds");
(tokenPairID, minAmount) = minTokenPairCrossChainAmount.at(index);
}
/**
* @notice Retrieves the minimum cross-chain amount for a specific token pair by ID.
* @dev Attempts to fetch the minAmount for the given tokenPairID from storage.
* If the pair is not configured, returns 0 (or handles default via tryGet).
* @param tokenPairID The unique ID of the token pair.
* @return minAmount The minimum cross-chain amount for the token pair (0 if not found).
*/
function getMinTokenPairCrossChainAmount(uint256 tokenPairID) public view virtual returns (uint256 minAmount) {
(, minAmount) = minTokenPairCrossChainAmount.tryGet(tokenPairID);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// 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
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
pragma solidity ^0.8.0;
import "./EnumerableSet.sol";
/**
* @dev Library for managing an enumerable variant of Solidity's
* https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
* type.
*
* Maps have the following properties:
*
* - Entries are added, removed, and checked for existence in constant time
* (O(1)).
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableMap for EnumerableMap.UintToAddressMap;
*
* // Declare a set state variable
* EnumerableMap.UintToAddressMap private myMap;
* }
* ```
*
* The following map types are supported:
*
* - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
* - `address -> uint256` (`AddressToUintMap`) since v4.6.0
* - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
* - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
* - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableMap.
* ====
*/
library EnumerableMap {
using EnumerableSet for EnumerableSet.Bytes32Set;
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Map type with
// bytes32 keys and values.
// The Map implementation uses private functions, and user-facing
// implementations (such as Uint256ToAddressMap) are just wrappers around
// the underlying Map.
// This means that we can only create new EnumerableMaps for types that fit
// in bytes32.
struct Bytes32ToBytes32Map {
// Storage of keys
EnumerableSet.Bytes32Set _keys;
mapping(bytes32 => bytes32) _values;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
map._values[key] = value;
return map._keys.add(key);
}
/**
* @dev Removes a key-value pair from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
delete map._values[key];
return map._keys.remove(key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
return map._keys.contains(key);
}
/**
* @dev Returns the number of key-value pairs in the map. O(1).
*/
function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
return map._keys.length();
}
/**
* @dev Returns the key-value pair stored at position `index` in the map. O(1).
*
* Note that there are no guarantees on the ordering of entries inside the
* array, and it may change when more entries are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
bytes32 key = map._keys.at(index);
return (key, map._values[key]);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
bytes32 value = map._values[key];
if (value == bytes32(0)) {
return (contains(map, key), bytes32(0));
} else {
return (true, value);
}
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key");
return value;
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToBytes32Map storage map,
bytes32 key,
string memory errorMessage
) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), errorMessage);
return value;
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
return map._keys.values();
}
// UintToUintMap
struct UintToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key)));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(UintToUintMap storage map, uint256 key, string memory errorMessage) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key), errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintToAddressMap
struct UintToAddressMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), address(uint160(uint256(value))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(value))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
UintToAddressMap storage map,
uint256 key,
string memory errorMessage
) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressToUintMap
struct AddressToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToUintMap storage map, address key) internal returns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(AddressToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (address(uint160(uint256(key))), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
AddressToUintMap storage map,
address key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// Bytes32ToUintMap
struct Bytes32ToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
return set(map._inner, key, bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
return remove(map._inner, key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
return contains(map._inner, key);
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (key, uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, key);
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
return uint256(get(map._inner, key));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToUintMap storage map,
bytes32 key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, key, errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
bytes32[] memory store = keys(map._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "../lib/BasicStorageLib.sol";
/**
* @title BasicStorage
* @dev Base contract for managing different types of storage data
* This contract provides basic storage functionality for various data types
* using the BasicStorageLib library
*
* Key features:
* - Multiple data type storage support
* - Library-based storage management
* - Internal storage access
*
* @custom:usage
* - Used as base contract for storage functionality
* - Provides structured storage for different data types
* - Supports inheritance for storage management
*/
contract BasicStorage {
/************************************************************
**
** VARIABLES
**
************************************************************/
//// basic variables
/**
* @dev Library usage declarations for different data types
*
* @custom:usage
* - UintData: For unsigned integer storage
* - BoolData: For boolean storage
* - AddressData: For address storage
* - BytesData: For bytes storage
* - StringData: For string storage
*/
using BasicStorageLib for BasicStorageLib.UintData;
using BasicStorageLib for BasicStorageLib.BoolData;
using BasicStorageLib for BasicStorageLib.AddressData;
using BasicStorageLib for BasicStorageLib.BytesData;
using BasicStorageLib for BasicStorageLib.StringData;
/**
* @dev Internal storage variables for different data types
*
* @custom:usage
* - uintData: Stores unsigned integers
* - boolData: Stores boolean values
* - addressData: Stores addresses
* - bytesData: Stores bytes data
* - stringData: Stores strings
*
* @custom:security
* - Internal visibility for controlled access
* - Library-based storage management
*/
BasicStorageLib.UintData internal uintData;
BasicStorageLib.BoolData internal boolData;
BasicStorageLib.AddressData internal addressData;
BasicStorageLib.BytesData internal bytesData;
BasicStorageLib.StringData internal stringData;
}// 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 './Owned.sol';
/**
* @title Halt
* @dev Contract for emergency stop functionality
* This contract provides functionality to halt and resume contract operations
* in emergency situations
*
* Key features:
* - Emergency stop mechanism
* - Access control through ownership
* - Modifiers for halted state checks
*
* @custom:security
* - Inherits Owned contract for ownership management
* - Only owner can halt/resume operations
* - State checks through modifiers
*/
contract Halt is Owned {
/**
* @dev Public state variable indicating if contract is halted
*
* @custom:usage
* - Controls contract operation state
* - Accessible for external queries
* - Modified through setHalt function
*/
bool public halted = false;
/**
* @dev Modifier to ensure contract is not halted
*
* @custom:requirements
* - Contract must not be in halted state
*
* @custom:reverts
* - If contract is halted
*/
modifier notHalted() {
require(!halted, "Smart contract is halted");
_;
}
/**
* @dev Modifier to ensure contract is halted
*
* @custom:requirements
* - Contract must be in halted state
*
* @custom:reverts
* - If contract is not halted
*/
modifier isHalted() {
require(halted, "Smart contract is not halted");
_;
}
/**
* @dev Sets the halted state of the contract
*
* @param halt Boolean indicating desired halted state
*
* @custom:requirements
* - Caller must be the contract owner
*
* @custom:effects
* - Updates halted state
* - Controls contract operation availability
*/
function setHalt(bool halt)
public
onlyOwner
{
halted = halt;
}
}// 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 Owned
* @dev Base contract for ownership management
* This contract provides functionality for managing contract ownership
* with support for ownership transfer and renunciation
*
* Key features:
* - Ownership assignment
* - Ownership transfer
* - Ownership renunciation
* - Two-step ownership transfer
*
* @custom:security
* - Owner-only access control
* - Safe ownership transfer
* - Ownership renunciation capability
*/
contract Owned {
/**
* @dev Emitted when ownership is transferred
*
* @param previousOwner Address of the previous owner
* @param newOwner Address of the new owner
*/
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Modifier to restrict function access to owner only
*
* @custom:requirements
* - Caller must be the contract owner
*
* @custom:reverts
* - If caller is not the owner
*/
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
/**
* @dev Public state variable for contract owner
*
* @custom:usage
* - Stores current owner address
* - Accessible for external queries
* - Modified through ownership functions
*/
address public owner;
/**
* @dev Constructor assigns initial owner
*
* @custom:effects
* - Sets initial owner to contract deployer
*/
constructor() {
owner = msg.sender;
}
/**
* @dev Public state variable for pending owner
*
* @custom:usage
* - Stores address of pending owner
* - Used in two-step ownership transfer
*/
address public newOwner;
/**
* @dev Transfers ownership to a new address
*
* @param _newOwner Address of the new owner
*
* @custom:requirements
* - Caller must be the current owner
* - New owner address must not be zero
*
* @custom:effects
* - Updates owner address
* - Emits OwnershipTransferred event
*/
function transferOwner(address _newOwner) public onlyOwner {
require(_newOwner != address(0), "New owner is the zero address");
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
/**
* @dev Initiates two-step ownership transfer
*
* @param _newOwner Address of the new owner
*
* @custom:requirements
* - Caller must be the current owner
*
* @custom:effects
* - Sets pending owner address
*/
function changeOwner(address _newOwner) public onlyOwner {
newOwner = _newOwner;
}
/**
* @dev Accepts pending ownership transfer
*
* @custom:requirements
* - Caller must be the pending owner
*
* @custom:effects
* - Updates owner address to pending owner
*/
function acceptOwnership() public {
if (msg.sender == newOwner) {
owner = newOwner;
}
}
/**
* @dev Renounces ownership of the contract
*
* @custom:requirements
* - Caller must be the current owner
*
* @custom:effects
* - Sets owner to zero address
* - Makes contract unowned
*/
function renounceOwnership() public onlyOwner {
owner = address(0);
}
}// 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 Proxy
* @dev Base contract for proxy pattern implementation
* This contract provides functionality for delegating calls to implementation contracts
* and supports contract upgradeability
*
* Key features:
* - Implementation contract delegation
* - Contract upgrade support
* - Fallback handling
* - Receive function support
*
* @custom:security
* - Implementation address validation
* - Safe delegatecall execution
* - Proper return data handling
*/
contract Proxy {
/**
* @dev Emitted when the implementation contract is upgraded
*
* @param implementation Address of the new implementation contract
*/
event Upgraded(address indexed implementation);
/**
* @dev Internal storage for implementation contract address
*
* @custom:usage
* - Stores current implementation address
* - Used for delegatecall operations
* - Modified through upgrade operations
*/
address internal _implementation;
/**
* @dev Returns the current implementation contract address
*
* @return Address of the current implementation contract
*/
function implementation() public view returns (address) {
return _implementation;
}
/**
* @dev Internal function to handle fallback calls
* Delegates all calls to the implementation contract
*
* @custom:requirements
* - Implementation contract must be set
*
* @custom:effects
* - Executes delegatecall to implementation
* - Handles return data
*
* @custom:reverts
* - If implementation contract is not set
* - If delegatecall fails
*/
function _fallback() internal {
address _impl = _implementation;
require(_impl != address(0), "implementation contract not set");
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize())
let result := delegatecall(gas(), _impl, ptr, calldatasize(), 0, 0)
let size := returndatasize()
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
/**
* @dev Fallback function to handle unknown function calls
* Delegates all calls to the implementation contract
*
* @custom:effects
* - Forwards call to _fallback
*/
fallback() external payable {
return _fallback();
}
/**
* @dev Receive function to handle incoming ETH
* Delegates all calls to the implementation contract
*
* @custom:effects
* - Forwards call to _fallback
*/
receive() external payable {
return _fallback();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
/**
* @title ReentrancyGuard
* @dev Abstract contract module that helps prevent reentrant calls to a function
*
* Key features:
* - Prevents reentrant function calls
* - Gas optimization for refunds
* - Support for nested function protection
*
* @custom:security
* - Prevents reentrancy attacks
* - Optimizes gas refunds
* - Supports private function calls
*
* @custom:usage
* - Inherit this contract to use nonReentrant modifier
* - Apply nonReentrant modifier to functions that need protection
* - Use private functions for nested calls
*/
abstract contract ReentrancyGuard {
/**
* @dev Private state variable to track reentrancy status
*
* @custom:usage
* - true: Function can be entered
* - false: Function is currently executing
*
* @custom:security
* - Prevents reentrant calls
* - Optimizes gas refunds
*/
bool private _notEntered;
/**
* @dev Constructor initializes the reentrancy guard
*
* @custom:effects
* - Sets initial state to true
* - Optimizes gas refunds
*
* @custom:security
* - Ensures proper initialization
* - Prevents initial reentrancy
*/
constructor () {
// Storing an initial non-zero value makes deployment a bit more
// expensive, but in exchange the refund on every call to nonReentrant
// will be lower in amount. Since refunds are capped to a percetange of
// the total transaction's gas, it is best to keep them low in cases
// like this one, to increase the likelihood of the full refund coming
// into effect.
_notEntered = true;
}
/**
* @dev Modifier to prevent reentrant calls to a function
*
* @custom:requirements
* - Function must not be currently executing
*
* @custom:effects
* - Sets _notEntered to false during execution
* - Restores _notEntered to true after execution
*
* @custom:reverts
* - If function is already executing
*
* @custom:usage
* - Apply to functions that need reentrancy protection
* - Use with private functions for nested calls
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_notEntered, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_notEntered = false;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_notEntered = true;
}
}// 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 "./CrossStorageV4.sol";
import "./lib/RapidityLibV4.sol";
import "./lib/NFTLibV1.sol";
/**
* @title CrossDelegateV4
* @dev Main implementation contract for cross-chain functionality
* This contract handles:
* - Cross-chain token transfers
* - NFT transfers
* - Fee management
* - Admin and operator role management
* - Transaction verification and execution
*/
contract CrossDelegateV4 is CrossStorageV4 {
using SafeMath for uint;
/**
* @notice Events emitted by the contract
*/
/**
* @notice Emitted when a new admin is set
* @param adminAccount The address of the new admin
*/
event SetAdmin(address adminAccount);
/**
* @notice Emitted when fees are updated for cross-chain operations
* @param srcChainID Source chain identifier
* @param destChainID Destination chain identifier
* @param contractFee Fee charged by the contract
* @param agentFee Fee charged by the agent
*/
event SetFee(uint indexed srcChainID, uint indexed destChainID, uint contractFee, uint agentFee);
/**
* @notice Emitted when token pair fees are updated
* @param tokenPairID ID of the token pair
* @param contractFee Fee charged by the contract for this token pair
*/
event SetTokenPairFee(uint indexed tokenPairID, uint contractFee);
/**
* @notice Emitted when a storeman group withdraws original coins to a receiver
* @param smgID ID of the storeman group
* @param timeStamp Timestamp of the withdrawal
* @param receiver Address of the receiver
* @param fee Shadow coin fee received by the storeman group
*/
event WithdrawHistoryFeeLogger(bytes32 indexed smgID, uint indexed timeStamp, address indexed receiver, uint fee);
/**
* @notice Emitted when operator status is configured
* @param operator Address of the operator
* @param enabled Whether the operator is enabled or disabled
*/
event ConfigOperator(address indexed operator, bool indexed enabled);
/**
* @notice Emitted when admin status is configured
* @param admin Address of the admin
* @param enabled Whether the admin is enabled or disabled
*/
event ConfigAdmin(address indexed admin, bool indexed enabled);
/**
*
* MODIFIERS
*
*/
/**
* @notice Ensures the caller has admin privileges
* @dev Checks if the caller is an admin, the main admin, or the owner
*/
modifier onlyAdmin() {
require(isAdmin[msg.sender] || msg.sender == admin || msg.sender == owner, "not admin");
_;
}
/**
* @notice Ensures the caller has operator privileges
* @dev Checks if the caller is an operator, an admin, the main admin, or the owner
*/
modifier onlyOperator() {
require(isOperator[msg.sender] || isAdmin[msg.sender] || msg.sender == admin || msg.sender == owner, "not operator");
_;
}
/**
* @notice Ensures the storeman group is in ready state
* @dev Checks if the specified storeman group is ready for operations
*/
modifier onlyReadySmg(bytes32 smgID) {
uint8 status;
uint startTime;
uint endTime;
(status,startTime,endTime) = storageData.smgAdminProxy.getStoremanGroupStatus(smgID);
require(status == uint8(GroupStatus.ready) && block.timestamp >= startTime && block.timestamp <= endTime, "PK is not ready");
_;
}
/**
*
* MANIPULATIONS
*
*/
/**
* @notice Initiates a cross-chain token transfer by locking original tokens
* @dev This function handles the initial step of cross-chain transfer where original tokens are locked
* @param smgID ID of the storeman group handling the transfer
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param value Amount of tokens to transfer
* @param userAccount Account information for receiving tokens on the destination chain
* Requirements:
* - Contract must not be halted
* - Storeman group must be ready
* - Value must be greater than 0
* - Token pair must exist
*/
function userLock(bytes32 smgID, uint tokenPairID, uint value, bytes calldata userAccount)
public
payable
virtual
notHalted
nonReentrant
onlyReadySmg(smgID)
{
address smgFeeProxy = getSmgFeeProxy();
RapidityLibV4.RapidityUserLockParams memory params = RapidityLibV4.RapidityUserLockParams({
smgID: smgID,
tokenPairID: tokenPairID,
value: value,
currentChainID: currentChainID,
tokenPairContractFee: mapTokenPairContractFee[tokenPairID],
etherTransferGasLimit: getEtherTransferGasLimit(),
destUserAccount: userAccount,
smgFeeProxy: smgFeeProxy
});
RapidityLibV4.userLock(storageData, params);
}
/**
* @notice Initiates a cross-chain token transfer by burning WRC20 tokens
* @dev This function handles the initial step of cross-chain transfer where WRC20 tokens are burned
* @param smgID ID of the storeman group handling the transfer
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param value Amount of tokens to transfer
* @param fee Fee for the transfer operation
* @param tokenAccount Address of the token contract
* @param userAccount Account information for receiving tokens on the destination chain
* Requirements:
* - Contract must not be halted
* - Storeman group must be ready
* - Value must be greater than fee
* - Token pair must exist
*/
function userBurn(bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, bytes calldata userAccount)
public
payable
virtual
notHalted
nonReentrant
onlyReadySmg(smgID)
{
address smgFeeProxy = getSmgFeeProxy();
RapidityLibV4.RapidityUserBurnParams memory params = RapidityLibV4.RapidityUserBurnParams({
smgID: smgID,
tokenPairID: tokenPairID,
value: value,
fee: fee,
currentChainID: currentChainID,
tokenPairContractFee: mapTokenPairContractFee[tokenPairID],
etherTransferGasLimit: getEtherTransferGasLimit(),
srcTokenAccount: tokenAccount,
destUserAccount: userAccount,
smgFeeProxy: smgFeeProxy
});
RapidityLibV4.userBurn(storageData, params);
}
/**
* @notice Mints WRC20 tokens for cross-chain transfer
* @dev This function is called by the storeman group to mint WRC20 tokens after receiving original tokens
* @param uniqueID Unique identifier for the cross-chain transaction
* @param smgID ID of the storeman group handling the transfer
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param value Amount of tokens to mint
* @param fee Fee for the transfer operation
* @param tokenAccount Address of the token contract
* @param userAccount Address of the user to receive the minted tokens
* @param r First part of the signature
* @param s Second part of the signature
* Requirements:
* - Contract must not be halted
* - Signature must be valid
* - Transaction must not be already processed
* - Value must be greater than fee
*/
function smgMint(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, address userAccount, bytes calldata r, bytes32 s)
external
notHalted
{
uint curveID;
bytes memory PK;
(curveID, PK) = acquireReadySmgInfo(smgID);
RapidityLibV4.RapiditySmgMintParams memory params = RapidityLibV4.RapiditySmgMintParams({
uniqueID: uniqueID,
smgID: smgID,
tokenPairID: tokenPairID,
value: value,
fee: fee,
destTokenAccount: tokenAccount,
destUserAccount: userAccount,
smgFeeProxy: (storageData.smgFeeProxy == address(0)) ? owner : storageData.smgFeeProxy // fix: Stack too deep
});
RapidityLibV4.smgMint(storageData, params);
bytes32 mHash = hashFunc(abi.encode(currentChainID, uniqueID, tokenPairID, value, fee, tokenAccount, userAccount));
verifySignature(curveID, mHash, PK, r, s);
}
/**
* @notice Releases original tokens in exchange for WRC20 tokens on Wanchain
* @dev This function is called by the storeman group to release original tokens after receiving WRC20 tokens
* @param uniqueID Unique identifier for the cross-chain transaction
* @param smgID ID of the storeman group handling the transfer
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param value Amount of tokens to release
* @param fee Fee for the transfer operation
* @param tokenAccount Address of the token contract
* @param userAccount Address of the user to receive the original tokens
* @param r First part of the signature
* @param s Second part of the signature
* Requirements:
* - Contract must not be halted
* - Storeman group must be ready and valid
* - Signature must be valid
* - Transaction must not be already processed
*/
function smgRelease(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, address userAccount, bytes calldata r, bytes32 s)
external
notHalted
{
uint curveID;
bytes memory PK;
(curveID, PK) = acquireReadySmgInfo(smgID);
RapidityLibV4.RapiditySmgReleaseParams memory params = RapidityLibV4.RapiditySmgReleaseParams({
uniqueID: uniqueID,
smgID: smgID,
tokenPairID: tokenPairID,
value: value,
fee: fee,
etherTransferGasLimit: getEtherTransferGasLimit(),
destTokenAccount: tokenAccount,
destUserAccount: userAccount,
smgFeeProxy: (storageData.smgFeeProxy == address(0)) ? owner : storageData.smgFeeProxy // fix: Stack too deep
});
RapidityLibV4.smgRelease(storageData, params);
bytes32 mHash = hashFunc(abi.encode(currentChainID, uniqueID, tokenPairID, value, fee, tokenAccount, userAccount));
verifySignature(curveID, mHash, PK, r, s);
}
/**
* @notice Sets the fees for cross-chain transfers between specific chains
* @dev This function allows operators to set both contract and agent fees for cross-chain operations
* @param param Struct containing the fee parameters:
* - srcChainID: Source chain ID
* - destChainID: Destination chain ID
* - contractFee: Fee charged by the contract
* - agentFee: Fee charged by the agent
* Requirements:
* - Caller must be an operator
*/
function setFee(SetFeesParam calldata param) public virtual onlyOperator {
storageData.mapContractFee[param.srcChainID][param.destChainID] = param.contractFee;
storageData.mapAgentFee[param.srcChainID][param.destChainID] = param.agentFee;
emit SetFee(param.srcChainID, param.destChainID, param.contractFee, param.agentFee);
}
/**
* @notice Sets fees for multiple cross-chain transfer pairs at once
* @dev This function allows operators to set fees for multiple chain pairs in a single transaction
* @param params Array of fee parameters for different chain pairs
* Requirements:
* - Caller must be an operator
*/
function setFees(SetFeesParam [] calldata params) public virtual onlyOperator {
for (uint i = 0; i < params.length; ++i) {
storageData.mapContractFee[params[i].srcChainID][params[i].destChainID] = params[i].contractFee;
storageData.mapAgentFee[params[i].srcChainID][params[i].destChainID] = params[i].agentFee;
emit SetFee(params[i].srcChainID, params[i].destChainID, params[i].contractFee, params[i].agentFee);
}
}
/**
* @notice Sets the contract fee for a specific token pair
* @dev This function allows operators to set the contract fee for cross-chain transfers of a specific token pair
* @param tokenPairID ID of the token pair
* @param contractFee Fee charged by the contract for this token pair
* Requirements:
* - Caller must be an operator
*/
function setTokenPairFee(uint256 tokenPairID, uint256 contractFee) external virtual onlyOperator {
mapTokenPairContractFee[tokenPairID] = contractFee;
emit SetTokenPairFee(tokenPairID, contractFee);
}
/**
* @notice Sets contract fees for multiple token pairs at once
* @dev This function allows operators to set contract fees for multiple token pairs in a single transaction
* @param params Array of token pair fee parameters
* Requirements:
* - Caller must be an operator
*/
function setTokenPairFees(SetTokenPairFeesParam [] calldata params) public virtual onlyOperator {
for (uint i = 0; i < params.length; ++i) {
mapTokenPairContractFee[params[i].tokenPairID] = params[i].contractFee;
emit SetTokenPairFee(params[i].tokenPairID, params[i].contractFee);
}
}
/**
* @notice Sets the current chain ID for the contract
* @dev This function allows admin to set the chain ID only if it hasn't been set before
* @param chainID The chain ID to set
* Requirements:
* - Caller must be admin
* - Chain ID must not be already set
*/
function setChainID(uint256 chainID) external virtual onlyAdmin {
if (currentChainID == 0) {
currentChainID = chainID;
}
}
/**
* @notice Computes the hash of input data using either keccak256 or sha256
* @dev This function is used for signature verification in cross-chain transactions
* @param data The input data to hash
* @return The computed hash value
*/
function hashFunc(bytes memory data) public view returns (bytes32){
if(hashType == 1) {
return keccak256(data);
} else {
return sha256(data);
}
}
/**
* @notice Sets the hash function type to be used for signature verification
* @dev This function allows the owner to switch between keccak256 (1) and sha256 (0)
* @param _hashType The hash function type to set (1 for keccak256, 0 for sha256)
* Requirements:
* - Caller must be the owner
*/
function setHashType(uint _hashType) external onlyOwner {
hashType = _hashType;
}
/**
* @notice Sets the admin address for the contract
* @dev This function allows the owner to change the admin address
* @param adminAccount The new admin address
* Requirements:
* - Caller must be the owner
*/
function setAdmin(address adminAccount) external onlyOwner {
admin = adminAccount;
emit SetAdmin(adminAccount);
}
/**
* @notice Sets a uint value in the contract's storage
* @dev This function allows admin to set values in the contract's storage using key-value pairs
* @param key The primary key for the storage location
* @param innerKey The secondary key for the storage location
* @param value The uint value to store
* Requirements:
* - Caller must be admin
*/
function setUintValue(bytes calldata key, bytes calldata innerKey, uint value) external virtual onlyAdmin {
return BasicStorageLib.setStorage(uintData, key, innerKey, value);
}
/**
* @notice Deletes a uint value from the contract's storage
* @dev This function allows admin to remove values from the contract's storage
* @param key The primary key for the storage location
* @param innerKey The secondary key for the storage location
* Requirements:
* - Caller must be admin
*/
function delUintValue(bytes calldata key, bytes calldata innerKey) external virtual onlyAdmin {
return BasicStorageLib.delStorage(uintData, key, innerKey);
}
/// @notice update the initialized state value of this contract
/// @param tokenManager address of the token manager
/// @param smgAdminProxy address of the storeman group admin
/// @param smgFeeProxy address of the proxy to store fee for storeman group
/// @param sigVerifier address of the signature verifier
function setPartners(address tokenManager, address smgAdminProxy, address smgFeeProxy, address, address sigVerifier)
external
onlyOwner
{
require(tokenManager != address(0) && smgAdminProxy != address(0) && sigVerifier != address(0),
"Parameter is invalid");
storageData.smgAdminProxy = IStoremanGroup(smgAdminProxy);
storageData.tokenManager = ITokenManager(tokenManager);
// storageData.quota = IQuota(quota);
storageData.smgFeeProxy = smgFeeProxy;
storageData.sigVerifier = ISignatureVerifier(sigVerifier);
}
/**
* @notice Withdraws accumulated historical fees to the foundation account
* @dev This function allows withdrawing fees accumulated by storeman groups
* @param smgIDs Array of storeman group IDs whose fees are to be withdrawn
* Requirements:
* - smgFeeProxy must be a valid address
*/
function smgWithdrawHistoryFee(bytes32 [] calldata smgIDs) external {
uint fee;
uint currentFee;
address smgFeeProxy = storageData.smgFeeProxy;
if (smgFeeProxy == address(0)) {
smgFeeProxy = owner;
}
require(smgFeeProxy != address(0), "invalid smgFeeProxy");
for (uint i = 0; i < smgIDs.length; ++i) {
currentFee = storageData.mapStoremanFee[smgIDs[i]];
delete storageData.mapStoremanFee[smgIDs[i]];
fee = fee.add(currentFee);
emit WithdrawHistoryFeeLogger(smgIDs[i], block.timestamp, smgFeeProxy, currentFee);
}
if (fee > 0) {
EtherTransfer.sendValue(payable(smgFeeProxy), fee, getEtherTransferGasLimit());
}
}
/**
* @notice Retrieves a uint value from the contract's storage
* @dev This function allows reading values from the contract's storage using key-value pairs
* @param key The primary key for the storage location
* @param innerKey The secondary key for the storage location
* @return The stored uint value
*/
function getUintValue(bytes calldata key, bytes calldata innerKey) public view returns (uint) {
return BasicStorageLib.getStorage(uintData, key, innerKey);
}
/**
* @notice Retrieves the accumulated fee for a specific storeman group
* @dev This function allows checking the fee amount that a storeman group has accumulated
* @param key The storeman group ID
* @return fee The accumulated fee amount for the storeman group
*/
function getStoremanFee(bytes32 key) external view returns(uint fee) {
fee = storageData.mapStoremanFee[key];
}
/**
* @notice Retrieves the fees for cross-chain transfers between specific chains
* @dev This function allows checking both contract and agent fees for a specific chain pair
* @param param Struct containing the chain IDs to check fees for
* @return fee Struct containing the contract and agent fees
*/
function getFee(GetFeesParam calldata param) public view returns(GetFeesReturn memory fee) {
fee.contractFee = storageData.mapContractFee[param.srcChainID][param.destChainID];
fee.agentFee = storageData.mapAgentFee[param.srcChainID][param.destChainID];
}
/**
* @notice Retrieves fees for multiple cross-chain transfer pairs at once
* @dev This function allows checking fees for multiple chain pairs in a single call
* @param params Array of chain pair parameters to check fees for
* @return fees Array of fee structs containing contract and agent fees for each chain pair
*/
function getFees(GetFeesParam [] calldata params) public view returns(GetFeesReturn [] memory fees) {
fees = new GetFeesReturn[](params.length);
for (uint i = 0; i < params.length; ++i) {
fees[i].contractFee = storageData.mapContractFee[params[i].srcChainID][params[i].destChainID];
fees[i].agentFee = storageData.mapAgentFee[params[i].srcChainID][params[i].destChainID];
}
}
/**
* @notice Retrieves the contract fee for a specific token pair
* @dev This function allows checking the contract fee for cross-chain transfers of a specific token pair
* @param tokenPairID ID of the token pair
* @return contractFee The contract fee for the specified token pair
*/
function getTokenPairFee(uint256 tokenPairID) external view returns(uint256 contractFee) {
contractFee = mapTokenPairContractFee[tokenPairID];
}
/**
* @notice Retrieves contract fees for multiple token pairs at once
* @dev This function allows checking contract fees for multiple token pairs in a single call
* @param tokenPairIDs Array of token pair IDs
* @return contractFees Array of contract fees for each token pair
*/
function getTokenPairFees(uint256[] calldata tokenPairIDs) external view returns(uint256 [] memory contractFees) {
contractFees = new uint256[](tokenPairIDs.length);
for (uint i = 0; i < tokenPairIDs.length; ++i) {
contractFees[i] = mapTokenPairContractFee[tokenPairIDs[i]];
}
}
/**
* @notice Retrieves the initialized state and partner addresses of the contract
* @dev This function returns the addresses of all core components and partner contracts
* @return tokenManager Address of the token manager contract
* @return smgAdminProxy Address of the storeman group admin proxy
* @return smgFeeProxy Address of the proxy to store fees for storeman group
* @return quota Address of the quota contract
* @return sigVerifier Address of the signature verifier contract
*/
function getPartners()
external
view
returns(address tokenManager, address smgAdminProxy, address smgFeeProxy, address quota, address sigVerifier)
{
tokenManager = address(storageData.tokenManager);
smgAdminProxy = address(storageData.smgAdminProxy);
smgFeeProxy = storageData.smgFeeProxy;
quota = address(storageData.quota);
sigVerifier = address(storageData.sigVerifier);
}
/** Private and Internal Functions */
/**
* @notice Retrieves information about a ready storeman group
* @dev This function returns the curve ID and public key of a storeman group that is ready for operations
* @param smgID ID of the storeman group to check
* @return curveID ID of the elliptic curve used by the storeman group
* @return PK Public key of the storeman group
* Requirements:
* - Storeman group must be in ready status
*/
function acquireReadySmgInfo(bytes32 smgID)
internal
view
returns (uint curveID, bytes memory PK)
{
uint8 status;
uint startTime;
uint endTime;
(,status,,,,curveID,,PK,,startTime,endTime) = storageData.smgAdminProxy.getStoremanGroupConfig(smgID);
require(status == uint8(GroupStatus.ready) && block.timestamp >= startTime && block.timestamp <= endTime, "PK is not ready");
return (curveID, PK);
}
/**
* @notice Retrieves information about an unregistered storeman group
* @dev This function returns the curve ID and public key of a storeman group that is not yet registered
* @param smgID ID of the storeman group to check
* @return curveID ID of the elliptic curve used by the storeman group
* @return PK Public key of the storeman group
* Requirements:
* - Storeman group must be in unregistered status
*/
function acquireUnregisteredSmgInfo(bytes32 smgID)
internal
view
returns (uint curveID, bytes memory PK)
{
uint8 status;
(,status,,,,curveID,,PK,,,) = storageData.smgAdminProxy.getStoremanGroupConfig(smgID);
require(status == uint8(GroupStatus.unregistered), "PK is not unregistered");
}
/**
* @notice Converts a bytes array to bytes32 starting from a specified offset
* @dev This function is used for extracting bytes32 values from a bytes array
* @param b The bytes array to convert
* @param offset The starting offset in the array
* @return result The converted bytes32 value
*/
function bytesToBytes32(bytes memory b, uint offset) internal pure returns (bytes32 result) {
assembly {
result := mload(add(add(b, offset), 32))
}
}
/**
* @notice Verifies a signature using the provided parameters
* @dev This function verifies a signature using the storeman group's public key and the signature components
* @param curveID ID of the elliptic curve used for verification
* @param message The message that was signed
* @param PK The public key of the signer
* @param r First component of the signature
* @param s Second component of the signature
* Requirements:
* - Signature must be valid according to the signature verifier contract
*/
function verifySignature(uint curveID, bytes32 message, bytes memory PK, bytes memory r, bytes32 s) internal {
bytes32 PKx = bytesToBytes32(PK, 0);
bytes32 PKy = bytesToBytes32(PK, 32);
bytes32 Rx = bytesToBytes32(r, 0);
bytes32 Ry = bytesToBytes32(r, 32);
require(storageData.sigVerifier.verify(curveID, s, PKx, PKy, Rx, Ry, message), "Signature verification failed");
}
/**
* @notice Gets the address of the storeman group fee proxy
* @dev This function returns the fee proxy address, falling back to the owner if not set
* @return The address of the fee proxy or owner
*/
function getSmgFeeProxy() internal view returns (address) {
address smgFeeProxy = storageData.smgFeeProxy;
return (smgFeeProxy == address(0)) ? owner : smgFeeProxy;
}
//*********************************************************************************************
//*********************************************************************************************
// NFT
/**
* @notice Implements the ERC721 token receiver interface
* @dev This function allows the contract to receive ERC721 tokens
* address - operator The address which called safeTransferFrom function
* address - from The address which previously owned the token
* uint256 - tokenId The token identifier
* bytes - data Additional data with no specified format
* @return The function selector of onERC721Received
*/
function onERC721Received(address, address, uint256, bytes memory)
public
pure
returns(bytes4)
{
return this.onERC721Received.selector;
}
/**
* @notice Implements the ERC1155 token receiver interface for single token transfers
* @dev This function allows the contract to receive ERC1155 tokens
* address - operator The address which called safeTransferFrom function
* address - from The address which previously owned the token
* uint256 - id The token identifier
* uint256 - value The amount of tokens being transferred
* bytes - data Additional data with no specified format
* @return The function selector of onERC1155Received
*/
function onERC1155Received(address, address, uint256, uint256, bytes memory)
public
pure
returns (bytes4)
{
return this.onERC1155Received.selector;
}
/**
* @notice Implements the ERC1155 token receiver interface for batch token transfers
* @dev This function allows the contract to receive multiple ERC1155 tokens in a single transaction
* address - operator The address which called safeBatchTransferFrom function
* address - from The address which previously owned the tokens
* uint256[] - ids Array of token identifiers
* uint256[] - values Array of token amounts
* bytes - data Additional data with no specified format
* @return The function selector of onERC1155BatchReceived
*/
function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata)
public
pure
returns (bytes4)
{
return this.onERC1155BatchReceived.selector;
}
/**
* @notice Initiates a cross-chain NFT transfer by locking original NFTs
* @dev This function handles the initial step of cross-chain NFT transfer where original NFTs are locked
* @param smgID ID of the storeman group handling the transfer
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param tokenIDs Array of NFT token IDs to transfer
* @param tokenValues Array of token values (amounts) for each NFT
* @param userAccount Account information for receiving NFTs on the destination chain
* Requirements:
* - Contract must not be halted
* - Storeman group must be ready
* - Number of tokens must be between 1 and maxBatchSize
* - Length of tokenIDs and tokenValues must match
*/
function userLockNFT(bytes32 smgID, uint tokenPairID, uint[] memory tokenIDs, uint[] memory tokenValues, bytes memory userAccount)
public
payable
virtual
notHalted
nonReentrant
onlyReadySmg(smgID)
{
require(tokenIDs.length > 0 && tokenIDs.length <= getMaxBatchSize(), "Invalid length");
require(tokenIDs.length == tokenValues.length, "Length mismatch");
NFTLibV1.RapidityUserLockNFTParams memory params = NFTLibV1.RapidityUserLockNFTParams({
smgID: smgID,
tokenPairID: tokenPairID,
tokenIDs: tokenIDs,
tokenValues: tokenValues,
currentChainID: currentChainID,
tokenPairContractFee: mapTokenPairContractFee[tokenPairID],
etherTransferGasLimit: getEtherTransferGasLimit(),
destUserAccount: userAccount,
smgFeeProxy: getSmgFeeProxy()
});
NFTLibV1.userLockNFT(storageData, params);
}
/**
* @notice Initiates a cross-chain NFT transfer by burning WRC721 tokens
* @dev This function handles the initial step of cross-chain NFT transfer where WRC721 tokens are burned
* @param smgID ID of the storeman group handling the transfer
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param tokenIDs Array of NFT token IDs to transfer
* @param tokenValues Array of token values (amounts) for each NFT
* @param tokenAccount Address of the token contract
* @param userAccount Account information for receiving NFTs on the destination chain
* Requirements:
* - Contract must not be halted
* - Storeman group must be ready
* - Number of tokens must be between 1 and maxBatchSize
* - Length of tokenIDs and tokenValues must match
*/
function userBurnNFT(bytes32 smgID, uint tokenPairID, uint[] memory tokenIDs, uint[] memory tokenValues, address tokenAccount, bytes memory userAccount)
public
payable
notHalted
nonReentrant
onlyReadySmg(smgID)
{
require(tokenIDs.length > 0 && tokenIDs.length <= getMaxBatchSize(), "Invalid length");
require(tokenIDs.length == tokenValues.length, "Length mismatch");
NFTLibV1.RapidityUserBurnNFTParams memory params = NFTLibV1.RapidityUserBurnNFTParams({
smgID: smgID,
tokenPairID: tokenPairID,
tokenIDs: tokenIDs,
tokenValues: tokenValues,
currentChainID: currentChainID,
tokenPairContractFee: mapTokenPairContractFee[tokenPairID],
etherTransferGasLimit: getEtherTransferGasLimit(),
srcTokenAccount: tokenAccount,
destUserAccount: userAccount,
smgFeeProxy: getSmgFeeProxy()
});
NFTLibV1.userBurnNFT(storageData, params);
}
/**
* @notice Mints WRC721 tokens for cross-chain NFT transfer
* @dev This function is called by the storeman group to mint WRC721 tokens after receiving original NFTs
* @param uniqueID Unique identifier for the cross-chain transaction
* @param smgID ID of the storeman group handling the transfer
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param tokenIDs Array of NFT token IDs to mint
* @param tokenValues Array of token values (amounts) for each NFT
* @param extData Additional data for the transfer
* @param tokenAccount Address of the token contract
* @param userAccount Address of the user to receive the minted NFTs
* @param r First part of the signature
* @param s Second part of the signature
* Requirements:
* - Contract must not be halted
* - Storeman group must be ready and valid
* - Signature must be valid
* - Transaction must not be already processed
*/
function smgMintNFT(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint[] memory tokenIDs, uint[] memory tokenValues, bytes memory extData, address tokenAccount, address userAccount, bytes memory r, bytes32 s)
public
notHalted
{
uint curveID;
bytes memory PK;
(curveID, PK) = acquireReadySmgInfo(smgID);
NFTLibV1.RapiditySmgMintNFTParams memory params = NFTLibV1.RapiditySmgMintNFTParams({
uniqueID: uniqueID,
smgID: smgID,
tokenPairID: tokenPairID,
tokenIDs: tokenIDs,
tokenValues: tokenValues,
extData: extData,
destTokenAccount: tokenAccount,
destUserAccount: userAccount
});
NFTLibV1.smgMintNFT(storageData, params);
bytes32 mHash = hashFunc(abi.encode(currentChainID, uniqueID, tokenPairID, tokenIDs, tokenValues, extData, tokenAccount, userAccount));
verifySignature(curveID, mHash, PK, r, s);
}
/**
* @notice Releases original NFTs in exchange for WRC721 tokens on Wanchain
* @dev This function is called by the storeman group to release original NFTs after receiving WRC721 tokens
* @param uniqueID Unique identifier for the cross-chain transaction
* @param smgID ID of the storeman group handling the transfer
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param tokenIDs Array of NFT token IDs to release
* @param tokenValues Array of token values (amounts) for each NFT
* @param tokenAccount Address of the token contract
* @param userAccount Address of the user to receive the original NFTs
* @param r First part of the signature
* @param s Second part of the signature
* Requirements:
* - Contract must not be halted
* - Storeman group must be ready and valid
* - Signature must be valid
* - Transaction must not be already processed
*/
function smgReleaseNFT(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint[] memory tokenIDs, uint[] memory tokenValues, address tokenAccount, address userAccount, bytes memory r, bytes32 s)
public
notHalted
{
uint curveID;
bytes memory PK;
(curveID, PK) = acquireReadySmgInfo(smgID);
NFTLibV1.RapiditySmgReleaseNFTParams memory params = NFTLibV1.RapiditySmgReleaseNFTParams({
uniqueID: uniqueID,
smgID: smgID,
tokenPairID: tokenPairID,
tokenIDs: tokenIDs,
tokenValues: tokenValues,
destTokenAccount: tokenAccount,
destUserAccount: userAccount
});
NFTLibV1.smgReleaseNFT(storageData, params);
bytes32 mHash = hashFunc(abi.encode(currentChainID, uniqueID, tokenPairID, tokenIDs, tokenValues, tokenAccount, userAccount));
verifySignature(curveID, mHash, PK, r, s);
}
/**
* @notice Sets the maximum batch size for NFT transfers
* @dev This function allows admin to set the maximum number of NFTs that can be transferred in a single transaction
* @param _maxBatchSize The new maximum batch size
* Requirements:
* - Caller must be admin
*/
function setMaxBatchSize(uint _maxBatchSize)
external
virtual
onlyAdmin
{
maxBatchSize = _maxBatchSize;
}
/**
* @notice Gets the maximum batch size for NFT transfers
* @dev This function returns the maximum number of NFTs that can be transferred in a single transaction
* @return The maximum batch size (defaults to 20 if not set)
*/
function getMaxBatchSize()
public
view
returns (uint)
{
if(maxBatchSize == 0) {
return 20;
}
return maxBatchSize;
}
/**
* @notice Gets the batch fee for NFT transfers
* @dev This function calculates the fee for transferring a batch of NFTs
* @param tokenPairID ID of the token pair
* @param batchLength Number of NFTs in the batch
* @return The calculated batch fee
*/
function getBatchFee(uint tokenPairID, uint batchLength)
external
view
returns (uint)
{
uint contractFee;
(, contractFee) = NFTLibV1.getTokenScAddrAndContractFee(storageData, tokenPairID, mapTokenPairContractFee[tokenPairID], currentChainID, batchLength);
return contractFee;
}
/**
* @notice Sets the gas limit for ether transfers
* @dev This function allows admin to set the gas limit used for ether transfers
* @param _etherTransferGasLimit The new gas limit
* Requirements:
* - Caller must be admin
*/
function setEtherTransferGasLimit(uint _etherTransferGasLimit)
external
virtual
onlyAdmin
{
etherTransferGasLimit = _etherTransferGasLimit;
}
/**
* @notice Gets the gas limit for ether transfers
* @dev This function returns the gas limit used for ether transfers
* @return The gas limit (defaults to 2300 if not set)
*/
function getEtherTransferGasLimit()
public
view
returns (uint)
{
if(etherTransferGasLimit == 0) {
return 2300;
}
return etherTransferGasLimit;
}
/**
* @notice Configures operator status for an address
* @dev This function allows admin to enable or disable operator privileges for an address
* @param _operator The address to configure
* @param enabled Whether to enable or disable operator privileges
* Requirements:
* - Caller must be admin
*/
function configOperator(address _operator, bool enabled) external onlyAdmin {
isOperator[_operator] = enabled;
emit ConfigOperator(_operator, enabled);
}
/**
* @notice Configures admin status for an address
* @dev This function allows owner to enable or disable admin privileges for an address
* @param _admin The address to configure
* @param enabled Whether to enable or disable admin privileges
* Requirements:
* - Caller must be owner
*/
function configAdmin(address _admin, bool enabled) external onlyOwner {
isAdmin[_admin] = enabled;
emit ConfigAdmin(_admin, enabled);
}
}// 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 "./CrossDelegateV4.sol";
/**
* @title CrossDelegateV5
* @dev Enhanced version of CrossDelegateV4 that adds NFT cross-chain ID management functionality
* This contract extends CrossDelegateV4 to provide:
* - NFT collection registration tracking
* - Cross-chain ID mapping for NFTs
* - Batch registration capabilities
*/
contract CrossDelegateV5 is CrossDelegateV4 {
/**
* @notice Mapping from NFT collection address to registration count
* @dev Tracks the number of NFTs registered for cross-chain operations from each collection
*/
mapping(address => uint256) public nftRegisterCount;
/**
* @notice Mapping from NFT collection and token ID to cross-chain ID
* @dev Stores the cross-chain ID assigned to each NFT
* uint256 - collection The address of the NFT collection
* uint256 - tokenId The ID of the NFT within the collection
* @return The assigned cross-chain ID
*/
mapping(address => mapping(uint256 => uint256)) public crossId;
/**
* @notice Mapping from NFT collection and cross-chain ID to NFT token ID
* @dev Stores the original NFT token ID for each cross-chain ID
* uint256 - collection The address of the NFT collection
* uint256 - crossId The cross-chain ID
* @return The original NFT token ID
*/
mapping(address => mapping(uint256 => uint256)) public crossIdToNftBaseInfo;
/**
* @notice Emitted when a new NFT is registered for cross-chain operations
* @param collection The address of the NFT collection
* @param tokenId The ID of the NFT within the collection
* @param crossId The assigned cross-chain ID
*/
event RegisterNftCrossId(address indexed collection, uint256 indexed tokenId, uint256 indexed crossId);
/**
* @notice Initiates a cross-chain NFT transfer by locking original NFTs
* @dev Overrides the parent function to add cross-chain ID registration
* @param smgID ID of the storeman group handling the transfer
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param tokenIDs Array of NFT token IDs to transfer
* @param tokenValues Array of token values (amounts) for each NFT
* @param userAccount Account information for receiving NFTs on the destination chain
*/
function userLockNFT(bytes32 smgID, uint tokenPairID, uint[] memory tokenIDs, uint[] memory tokenValues, bytes memory userAccount)
public
payable
override
{
super.userLockNFT(smgID, tokenPairID, tokenIDs, tokenValues, userAccount);
address tokenScAddr = localTokenAddress(tokenPairID);
uint count = tokenIDs.length;
for (uint i = 0; i < count; i++) {
registerNftCrossId(tokenScAddr, tokenIDs[i]);
}
}
/**
* @notice Registers a new NFT for cross-chain operations
* @dev Assigns a unique cross-chain ID to an NFT if not already registered
* @param collection The address of the NFT collection
* @param tokenId The ID of the NFT within the collection
* @return The assigned cross-chain ID
*/
function registerNftCrossId(address collection, uint tokenId) internal returns (uint256) {
if (crossId[collection][tokenId] > 0) {
return crossId[collection][tokenId];
} else {
nftRegisterCount[collection] += 1;
crossId[collection][tokenId] = nftRegisterCount[collection];
crossIdToNftBaseInfo[collection][nftRegisterCount[collection]] = tokenId;
emit RegisterNftCrossId(collection, tokenId, nftRegisterCount[collection]);
return nftRegisterCount[collection];
}
}
/**
* @notice Registers multiple NFTs for cross-chain operations in a single transaction
* @dev Allows admin to register multiple NFTs from different collections at once
* @param collection Array of NFT collection addresses
* @param tokenIds Array of NFT token IDs
* Requirements:
* - Caller must be admin
* - Length of collection array must match length of tokenIds array
*/
function batchRegisterNftCrossId(address[] memory collection, uint256[] memory tokenIds) external onlyAdmin {
require(collection.length == tokenIds.length, "CrossDelegateV5: collection length not equal to tokenIds length");
for (uint256 i = 0; i < tokenIds.length; i++) {
registerNftCrossId(collection[i], tokenIds[i]);
}
}
/**
* @notice Retrieves the local token address for a given token pair
* @dev Determines the correct token address based on the current chain ID
* @param tokenPairID ID of the token pair
* @return The address of the token contract on the current chain
* Requirements:
* - Token pair must exist
* - Current chain must be either source or destination chain
*/
function localTokenAddress(uint tokenPairID)
public
view
returns (address)
{
ITokenManager tokenManager = storageData.tokenManager;
uint fromChainID;
uint toChainID;
bytes memory fromTokenAccount;
bytes memory toTokenAccount;
(fromChainID,fromTokenAccount,toChainID,toTokenAccount) = tokenManager.getTokenPairInfo(tokenPairID);
require(fromChainID != 0, "Token does not exist");
address tokenScAddr;
if (currentChainID == fromChainID) {
tokenScAddr = CrossTypes.bytesToAddress(fromTokenAccount);
} else if (currentChainID == toChainID) {
tokenScAddr = CrossTypes.bytesToAddress(toTokenAccount);
} else {
require(false, "Invalid token pair");
}
return tokenScAddr;
}
}// 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 "../components/BasicStorage.sol";
import "./lib/CrossTypes.sol";
import "./lib/HTLCTxLib.sol";
import "./lib/RapidityTxLib.sol";
/**
* @title CrossStorage
* @dev Storage contract for cross-chain functionality that manages cross-chain related data
* This contract inherits from BasicStorage and provides storage for:
* - HTLC (Hash Time-Locked Contract) transactions
* - Rapidity transactions
* - Cross-chain types and data
*/
contract CrossStorage is BasicStorage {
using HTLCTxLib for HTLCTxLib.Data;
using RapidityTxLib for RapidityTxLib.Data;
/************************************************************
**
** VARIABLES
**
************************************************************/
/**
* @dev Internal storage for cross-chain related data
*/
CrossTypes.Data internal storageData;
/**
* @notice Time period for which assets are locked in HTLC transactions
* @dev Default value is 36 hours (3600*36 seconds)
*/
uint public lockedTime = uint(3600*36);
/**
* @notice Timeout period for storeman group fee receiver address changes
* @dev Since storeman group admin receiver address may be changed, system ensures:
* - New address becomes valid after this timeout
* - Old address becomes invalid after this timeout
* Default value is 10 minutes (10*60 seconds)
*/
uint public smgFeeReceiverTimeout = uint(10*60);
/**
* @notice Enumeration of possible states for a storeman group
* @dev States:
* - none: Initial state
* - initial: Group has been initialized
* - curveSeted: Curve parameters have been set
* - failed: Group setup has failed
* - selected: Group has been selected
* - ready: Group is ready for operations
* - unregistered: Group has been unregistered
* - dismissed: Group has been dismissed
*/
enum GroupStatus { none, initial, curveSeted, failed, selected, ready, unregistered, dismissed }
}// 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 "../components/Proxy.sol";
import "../components/Halt.sol";
import "../components/ReentrancyGuard.sol";
import "./CrossStorage.sol";
/**
* @title CrossStorageV2
* @dev Enhanced version of CrossStorage that adds chain ID and fee management functionality
* This contract inherits from:
* - CrossStorage: Base storage functionality
* - ReentrancyGuard: To prevent reentrancy attacks
* - Halt: To provide emergency stop functionality
* - Proxy: To enable implementation upgrades
*/
contract CrossStorageV2 is CrossStorage, ReentrancyGuard, Halt, Proxy {
/************************************************************
**
** VARIABLES
**
************************************************************/
/** STATE VARIABLES **/
/**
* @notice The chain ID of the current network
* @dev Used to identify the source chain in cross-chain operations
*/
uint256 public currentChainID;
/**
* @notice The address of the contract administrator
* @dev Has special privileges for managing the contract
*/
address public admin;
/** STRUCTURES **/
/**
* @notice Parameters for setting cross-chain fees
* @dev Used when configuring fees for specific chain pairs
* @param srcChainID Source chain identifier
* @param destChainID Destination chain identifier
* @param contractFee Fee charged by the contract
* @param agentFee Fee charged by the agent
*/
struct SetFeesParam {
uint256 srcChainID;
uint256 destChainID;
uint256 contractFee;
uint256 agentFee;
}
/**
* @notice Parameters for retrieving cross-chain fees
* @dev Used when querying fees for specific chain pairs
* @param srcChainID Source chain identifier
* @param destChainID Destination chain identifier
*/
struct GetFeesParam {
uint256 srcChainID;
uint256 destChainID;
}
/**
* @notice Return structure for fee queries
* @dev Contains the fee information for a specific chain pair
* @param contractFee Fee charged by the contract
* @param agentFee Fee charged by the agent
*/
struct GetFeesReturn {
uint256 contractFee;
uint256 agentFee;
}
}// 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 "./CrossStorageV2.sol";
/**
* @title CrossStorageV3
* @dev Enhanced version of CrossStorageV2 that adds token pair fee management functionality
* This contract inherits from CrossStorageV2 and provides:
* - Mapping for token pair contract fees
* - Structure for setting token pair fees
*/
contract CrossStorageV3 is CrossStorageV2 {
/************************************************************
**
** VARIABLES
**
************************************************************/
/** STATE VARIABLES **/
/**
* @notice Mapping from token pair ID to contract fee
* @dev Used to store and retrieve fees for specific token pairs
* uint256 - tokenPairID Unique identifier for a token pair
* uint256 - contractFee The fee charged by the contract for this token pair
*/
mapping(uint256 => uint256) mapTokenPairContractFee;
/**
* @notice Parameters for setting token pair fees
* @dev Used when configuring fees for specific token pairs
* @param tokenPairID Unique identifier for a token pair
* @param contractFee The fee to be charged by the contract for this token pair
*/
struct SetTokenPairFeesParam {
uint256 tokenPairID;
uint256 contractFee;
}
}// 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 "./CrossStorageV3.sol";
/**
* @title CrossStorageV4
* @dev Enhanced version of CrossStorageV3 that adds batch processing, gas limits, and role-based access control
* This contract inherits from CrossStorageV3 and provides:
* - Maximum batch size configuration
* - Gas limit settings for ether transfers
* - Hash function type selection
* - Role-based access control for admin and operator roles
*/
contract CrossStorageV4 is CrossStorageV3 {
/************************************************************
**
** VARIABLES
**
************************************************************/
/**
* @notice Maximum number of transactions that can be processed in a single batch
* @dev Used to limit the size of batch operations for gas optimization
*/
uint internal maxBatchSize;
/**
* @notice Gas limit for ether transfer operations
* @dev Used to estimate gas costs for cross-chain ether transfers
*/
uint internal etherTransferGasLimit;
/**
* @notice Type of hash function to be used
* @dev 0: sha256, 1: keccak256
* Used for generating transaction hashes in cross-chain operations
*/
uint public hashType; // 0: sha256, 1: keccak256
/**
* @notice Mapping of addresses to admin role status
* @dev Used for role-based access control of administrative functions
*/
mapping(address => bool) public isAdmin;
/**
* @notice Mapping of addresses to operator role status
* @dev Used for role-based access control of operational functions
*/
mapping(address => bool) public isOperator;
}// 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;
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "./RapidityTxLib.sol";
import "./CrossTypes.sol";
import "../../interfaces/ITokenManager.sol";
import "./EtherTransfer.sol";
/**
* @title NFTLibV1
* @dev Library for managing NFT cross-chain operations
* This library provides functionality for:
* - NFT locking and unlocking
* - NFT minting and burning
* - Cross-chain NFT transfer management
*/
library NFTLibV1 {
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 NFT locking operations
* @dev Used when users want to lock their NFTs for cross-chain transfer
* @param smgID ID of the selected storeman group
* @param tokenPairID ID of the token pair for cross-chain transfer
* @param tokenIDs Array of NFT token IDs to be locked
* @param tokenValues Array of NFT token values (for ERC1155)
* @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 RapidityUserLockNFTParams {
bytes32 smgID; /// ID of storeman group which user has selected
uint tokenPairID; /// token pair id on cross chain
uint[] tokenIDs; /// NFT token Ids
uint[] tokenValues; /// NFT token values
uint currentChainID; /// current chain ID
uint tokenPairContractFee; /// fee of token pair
uint etherTransferGasLimit; /// exchange token fee
bytes destUserAccount; /// account of shadow chain, used to receive token
address smgFeeProxy; /// address of the proxy to store fee for storeman group
}
/**
* @notice Parameters for storeman-initiated NFT minting operations
* @dev Used when storeman group mints NFTs 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 tokenIDs Array of NFT token IDs to be minted
* @param tokenValues Array of NFT token values (for ERC1155)
* @param extData Additional data for storeman operations
* @param destTokenAccount Destination token contract address
* @param destUserAccount Destination user account address
*/
struct RapiditySmgMintNFTParams {
bytes32 uniqueID; /// Rapidity random number
bytes32 smgID; /// ID of storeman group which user has selected
uint tokenPairID; /// token pair id on cross chain
uint[] tokenIDs; /// NFT token Ids
uint[] tokenValues; /// NFT token values
bytes extData; /// storeman data
address destTokenAccount; /// shadow token account
address destUserAccount; /// account of shadow chain, used to receive token
}
/**
* @notice Parameters for user-initiated NFT burning operations
* @dev Used when users want to burn their NFTs for cross-chain transfer
* @param smgID ID of the selected storeman group
* @param tokenPairID ID of the token pair
* @param tokenIDs Array of NFT token IDs to be burned
* @param tokenValues Array of NFT token values (for ERC1155)
* @param currentChainID ID of the current blockchain
* @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 RapidityUserBurnNFTParams {
bytes32 smgID; /// ID of storeman group which user has selected
uint tokenPairID; /// token pair id on cross chain
uint[] tokenIDs; /// NFT token Ids
uint[] tokenValues; /// NFT token values
uint currentChainID; /// current chain ID
uint tokenPairContractFee; /// fee of token pair
uint etherTransferGasLimit; /// exchange token fee
address srcTokenAccount; /// shadow token account
bytes destUserAccount; /// account of token destination chain, used to receive token
address smgFeeProxy; /// address of the proxy to store fee for storeman group
}
/**
* @notice Parameters for storeman-initiated NFT release operations
* @dev Used when storeman group releases NFTs 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 tokenIDs Array of NFT token IDs to be released
* @param tokenValues Array of NFT token values (for ERC1155)
* @param destTokenAccount Destination token contract address
* @param destUserAccount Destination user account address
*/
struct RapiditySmgReleaseNFTParams {
bytes32 uniqueID; /// Rapidity random number
bytes32 smgID; /// ID of storeman group which user has selected
uint tokenPairID; /// token pair id on cross chain
uint[] tokenIDs; /// NFT token Ids
uint[] tokenValues; /// NFT token values
address destTokenAccount; /// original token/coin account
address destUserAccount; /// account of token original chain, used to receive token
}
/**
* @notice Event emitted when NFTs 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 keys Array of event keys
* @param values Array of event values
*/
event UserLockNFT(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, string[] keys, bytes[] values);
/**
* @notice Event emitted when NFTs 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 keys Array of event keys
* @param values Array of event values
*/
event UserBurnNFT(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, string[] keys, bytes[] values);
/**
* @notice Event emitted when NFTs 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 keys Array of event keys
* @param values Array of event values
*/
event SmgMintNFT(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, string[] keys, bytes[] values);
/**
* @notice Event emitted when NFTs 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 keys Array of event keys
* @param values Array of event values
*/
event SmgReleaseNFT(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, string[] keys, bytes[] values);
/**
* @notice Gets the token contract address and contract fee for a token pair
* @dev Calculates the appropriate contract fee based on chain IDs and batch size
* @param storageData Cross storage data
* @param tokenPairID ID of the token pair
* @param tokenPairContractFee Fee for the token pair contract
* @param currentChainID ID of the current blockchain
* @param batchLength Length of the batch operation
* @return tokenScAddr Address of the token contract
* @return contractFee Calculated contract fee
* Requirements:
* - Token pair must exist
* - Current chain ID must be valid
*/
function getTokenScAddrAndContractFee(CrossTypes.Data storage storageData, uint tokenPairID, uint tokenPairContractFee, uint currentChainID, uint batchLength)
public
view
returns (address, uint)
{
ITokenManager tokenManager = storageData.tokenManager;
uint fromChainID;
uint toChainID;
bytes memory fromTokenAccount;
bytes memory toTokenAccount;
(fromChainID,fromTokenAccount,toChainID,toTokenAccount) = tokenManager.getTokenPairInfo(tokenPairID);
require(fromChainID != 0, "Token does not exist");
uint contractFee = tokenPairContractFee;
address tokenScAddr;
if (currentChainID == fromChainID) {
if (contractFee == 0) {
contractFee = storageData.mapContractFee[fromChainID][toChainID];
}
if (contractFee == 0) {
contractFee = storageData.mapContractFee[fromChainID][0];
}
tokenScAddr = CrossTypes.bytesToAddress(fromTokenAccount);
} else if (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) {
contractFee = contractFee.mul(9 + batchLength).div(10);
}
return (tokenScAddr, contractFee);
}
/**
* @notice Locks NFTs for cross-chain transfer
* @dev Handles the locking of ERC721 and ERC1155 tokens
* @param storageData Cross storage data
* @param params Parameters for the NFT locking operation
* Requirements:
* - NFT type must be valid (ERC721 or ERC1155)
* - User must have sufficient balance
* - Contract must have approval to transfer tokens
*/
function userLockNFT(CrossTypes.Data storage storageData, RapidityUserLockNFTParams memory params)
public
{
address tokenScAddr;
uint contractFee;
(tokenScAddr, contractFee) = getTokenScAddrAndContractFee(storageData, params.tokenPairID, params.tokenPairContractFee, params.currentChainID, params.tokenIDs.length);
if (contractFee > 0) {
EtherTransfer.sendValue(payable(params.smgFeeProxy), contractFee, params.etherTransferGasLimit);
}
uint left = (msg.value).sub(contractFee);
uint8 tokenCrossType = storageData.tokenManager.mapTokenPairType(params.tokenPairID);
if (tokenCrossType == uint8(TokenCrossType.ERC721)) {
for(uint idx = 0; idx < params.tokenIDs.length; ++idx) {
IERC721(tokenScAddr).safeTransferFrom(msg.sender, address(this), params.tokenIDs[idx], "");
}
} else if(tokenCrossType == uint8(TokenCrossType.ERC1155)) {
IERC1155(tokenScAddr).safeBatchTransferFrom(msg.sender, address(this), params.tokenIDs, params.tokenValues, "");
}
else{
require(false, "Invalid NFT type");
}
if (left != 0) {
EtherTransfer.sendValue(payable(msg.sender), left, params.etherTransferGasLimit);
}
string[] memory keys = new string[](4);
bytes[] memory values = new bytes[](4);
keys[0] = "tokenIDs:uint256[]";
values[0] = abi.encode(params.tokenIDs);
keys[1] = "tokenValues:uint256[]";
values[1] = abi.encode(params.tokenValues);
keys[2] = "userAccount:bytes";
values[2] = params.destUserAccount;
keys[3] = "contractFee:uint256";
values[3] = abi.encodePacked(contractFee);
emit UserLockNFT(params.smgID, params.tokenPairID, tokenScAddr, keys, values);
}
/**
* @notice Burns NFTs for cross-chain transfer
* @dev Handles the burning of ERC721 and ERC1155 tokens
* @param storageData Cross storage data
* @param params Parameters for the NFT burning operation
* Requirements:
* - NFT type must be valid (ERC721 or ERC1155)
* - User must have sufficient balance
* - Contract must have approval to burn tokens
*/
function userBurnNFT(CrossTypes.Data storage storageData, RapidityUserBurnNFTParams memory params)
public
{
address tokenScAddr;
uint contractFee;
(tokenScAddr, contractFee) = getTokenScAddrAndContractFee(storageData, params.tokenPairID, params.tokenPairContractFee, params.currentChainID, params.tokenIDs.length);
ITokenManager tokenManager = storageData.tokenManager;
uint8 tokenCrossType = tokenManager.mapTokenPairType(params.tokenPairID);
require((tokenCrossType == uint8(TokenCrossType.ERC721) || tokenCrossType == uint8(TokenCrossType.ERC1155)), "Invalid NFT type");
ITokenManager(tokenManager).burnNFT(uint(tokenCrossType), tokenScAddr, msg.sender, params.tokenIDs, params.tokenValues);
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);
}
string[] memory keys = new string[](4);
bytes[] memory values = new bytes[](4);
keys[0] = "tokenIDs:uint256[]";
values[0] = abi.encode(params.tokenIDs);
keys[1] = "tokenValues:uint256[]";
values[1] = abi.encode(params.tokenValues);
keys[2] = "userAccount:bytes";
values[2] = params.destUserAccount;
keys[3] = "contractFee:uint256";
values[3] = abi.encodePacked(contractFee);
emit UserBurnNFT(params.smgID, params.tokenPairID, tokenScAddr, keys, values);
}
/**
* @notice Mints NFTs on the destination chain
* @dev Handles the minting of ERC721 and ERC1155 tokens
* @param storageData Cross storage data
* @param params Parameters for the NFT minting operation
* Requirements:
* - NFT type must be valid (ERC721 or ERC1155)
* - Storeman group must have permission to mint
*/
function smgMintNFT(CrossTypes.Data storage storageData, RapiditySmgMintNFTParams memory params)
public
{
storageData.rapidityTxData.addRapidityTx(params.uniqueID);
ITokenManager tokenManager = storageData.tokenManager;
uint8 tokenCrossType = tokenManager.mapTokenPairType(params.tokenPairID);
require((tokenCrossType == uint8(TokenCrossType.ERC721) || tokenCrossType == uint8(TokenCrossType.ERC1155)), "Invalid NFT type");
ITokenManager(tokenManager).mintNFT(uint(tokenCrossType), params.destTokenAccount, params.destUserAccount, params.tokenIDs, params.tokenValues, params.extData);
string[] memory keys = new string[](5);
bytes[] memory values = new bytes[](5);
keys[0] = "tokenIDs:uint256[]";
values[0] = abi.encode(params.tokenIDs);
keys[1] = "tokenValues:uint256[]";
values[1] = abi.encode(params.tokenValues);
keys[2] = "tokenAccount:address";
values[2] = abi.encodePacked(params.destTokenAccount);
keys[3] = "userAccount:address";
values[3] = abi.encodePacked(params.destUserAccount);
keys[4] = "extData:bytes";
values[4] = params.extData;
emit SmgMintNFT(params.uniqueID, params.smgID, params.tokenPairID, keys, values);
}
/**
* @notice Releases NFTs on the original chain
* @dev Handles the release of ERC721 and ERC1155 tokens
* @param storageData Cross storage data
* @param params Parameters for the NFT release operation
* Requirements:
* - NFT type must be valid (ERC721 or ERC1155)
* - Storeman group must have permission to release
*/
function smgReleaseNFT(CrossTypes.Data storage storageData, RapiditySmgReleaseNFTParams memory params)
public
{
storageData.rapidityTxData.addRapidityTx(params.uniqueID);
uint8 tokenCrossType = storageData.tokenManager.mapTokenPairType(params.tokenPairID);
if (tokenCrossType == uint8(TokenCrossType.ERC721)) {
for(uint idx = 0; idx < params.tokenIDs.length; ++idx) {
IERC721(params.destTokenAccount).safeTransferFrom(address(this), params.destUserAccount, params.tokenIDs[idx], "");
}
}
else if(tokenCrossType == uint8(TokenCrossType.ERC1155)) {
IERC1155(params.destTokenAccount).safeBatchTransferFrom(address(this), params.destUserAccount, params.tokenIDs, params.tokenValues, "");
}
else {
require(false, "Invalid NFT type");
}
string[] memory keys = new string[](4);
bytes[] memory values = new bytes[](4);
keys[0] = "tokenIDs:uint256[]";
values[0] = abi.encode(params.tokenIDs);
keys[1] = "tokenValues:uint256[]";
values[1] = abi.encode(params.tokenValues);
keys[2] = "tokenAccount:address";
values[2] = abi.encodePacked(params.destTokenAccount);
keys[3] = "userAccount:address";
values[3] = abi.encodePacked(params.destUserAccount);
emit SmgReleaseNFT(params.uniqueID, params.smgID, params.tokenPairID, keys, values);
}
}// 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
/*
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);
}// 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;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
/**
* @title BasicStorageLib
* @dev Library for basic storage operations with support for multiple data types
* This library provides a structured approach to contract storage with a two-level key system
*
* Key features:
* - Support for multiple data types (uint, bool, address, bytes, string)
* - Two-level key storage system for flexible data organization
* - CRUD operations for each data type with consistent interface
* - Gas-efficient storage patterns
*
* @custom:security
* - Internal access only to prevent unauthorized storage manipulation
* - Safe storage operations with proper type enforcement
* - Type-specific operations to prevent type confusion
* - Consistent interface reduces likelihood of implementation errors
*
* @custom:usage
* - Used as a foundation for complex contract storage patterns
* - Enables modular and organized data storage in contracts
* - Simplifies storage access with standardized methods
* - Perfect for contracts with diverse data storage needs
*/
library BasicStorageLib {
/**
* @dev Structure for storing uint values
* Provides a two-level nested mapping for uint storage
*
* @custom:usage
* - Stores uint values with two-level key system for hierarchical data
* - Used for numeric data storage such as balances, timestamps, amounts
* - Primary key often represents a category, while innerKey represents specific item
* - Essential for tracking numeric values in complex systems
*/
struct UintData {
mapping(bytes => mapping(bytes => uint)) _storage;
}
/**
* @dev Structure for storing boolean values
* Provides a two-level nested mapping for boolean storage
*
* @custom:usage
* - Stores boolean values with two-level key system for hierarchical data
* - Used for flag and state storage such as activation status or permissions
* - Efficient for representing binary states (true/false)
* - Perfect for access control and feature toggles
*/
struct BoolData {
mapping(bytes => mapping(bytes => bool)) _storage;
}
/**
* @dev Structure for storing address values
* Provides a two-level nested mapping for address storage
*
* @custom:usage
* - Stores address values with two-level key system for hierarchical data
* - Used for contract and account address storage
* - Essential for tracking ownership, relationships between entities
* - Enables role-based systems and contract registries
*/
struct AddressData {
mapping(bytes => mapping(bytes => address)) _storage;
}
/**
* @dev Structure for storing bytes values
* Provides a two-level nested mapping for bytes storage
*
* @custom:usage
* - Stores bytes values with two-level key system for hierarchical data
* - Used for raw data storage such as cryptographic proofs, signatures
* - Perfect for storing variable-length binary data
* - Enables storage of complex serialized structures
*/
struct BytesData {
mapping(bytes => mapping(bytes => bytes)) _storage;
}
/**
* @dev Structure for storing string values
* Provides a two-level nested mapping for string storage
*
* @custom:usage
* - Stores string values with two-level key system for hierarchical data
* - Used for text data storage such as names, descriptions, metadata
* - Human-readable information storage
* - Suitable for configuration parameters and user-facing content
*/
struct StringData {
mapping(bytes => mapping(bytes => string)) _storage;
}
/**
* @dev Set uint value in storage
* Assigns a uint value to a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization (e.g., user ID, token type)
* @param innerKey Secondary key for specific attribute (e.g., balance, timestamp)
* @param value Unsigned integer value to store
*
* @custom:effects
* - Updates storage with new value, overwriting any existing value
* - Gas usage scales with key sizes, not with value size
* - Optimized for single-slot storage operations
*/
function setStorage(UintData storage self, bytes memory key, bytes memory innerKey, uint value) internal {
self._storage[key][innerKey] = value;
}
/**
* @dev Get uint value from storage
* Retrieves a uint value from a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization
* @param innerKey Secondary key for specific attribute
* @return Stored uint value, or 0 if no value has been set
*
* @custom:effects
* - Read-only operation that doesn't modify state
* - Returns default value (0) if entry doesn't exist
* - Gas cost is constant regardless of value stored
*/
function getStorage(UintData storage self, bytes memory key, bytes memory innerKey) internal view returns (uint) {
return self._storage[key][innerKey];
}
/**
* @dev Delete uint value from storage
* Removes a uint value from a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization
* @param innerKey Secondary key for specific attribute
*
* @custom:effects
* - Removes value from storage, setting it to default value (0)
* - Gas refund is provided when clearing storage to zero
* - Frees up storage space, potentially reducing contract storage costs
*/
function delStorage(UintData storage self, bytes memory key, bytes memory innerKey) internal {
delete self._storage[key][innerKey];
}
/**
* @dev Set boolean value in storage
* Assigns a boolean value to a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization (e.g., feature name, user ID)
* @param innerKey Secondary key for specific flag (e.g., active, approved)
* @param value Boolean value to store
*
* @custom:effects
* - Updates storage with new value, overwriting any existing value
* - Gas efficient for storing binary state information
* - Packs values efficiently in storage
*/
function setStorage(BoolData storage self, bytes memory key, bytes memory innerKey, bool value) internal {
self._storage[key][innerKey] = value;
}
/**
* @dev Get boolean value from storage
* Retrieves a boolean value from a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization
* @param innerKey Secondary key for specific flag
* @return Stored boolean value, or false if no value has been set
*
* @custom:effects
* - Read-only operation that doesn't modify state
* - Returns default value (false) if entry doesn't exist
* - Gas efficient for checking state conditions
*/
function getStorage(BoolData storage self, bytes memory key, bytes memory innerKey) internal view returns (bool) {
return self._storage[key][innerKey];
}
/**
* @dev Delete boolean value from storage
* Removes a boolean value from a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization
* @param innerKey Secondary key for specific flag
*
* @custom:effects
* - Removes value from storage, setting it to default value (false)
* - Gas refund is provided when clearing storage to zero
* - Particularly efficient for boolean values
*/
function delStorage(BoolData storage self, bytes memory key, bytes memory innerKey) internal {
delete self._storage[key][innerKey];
}
/**
* @dev Set address value in storage
* Assigns an address value to a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization (e.g., role name, contract type)
* @param innerKey Secondary key for specific relationship (e.g., owner, delegate)
* @param value Ethereum address to store
*
* @custom:effects
* - Updates storage with new address, overwriting any existing value
* - Stores full 20-byte Ethereum addresses
* - Critical for tracking contract relationships and ownership
*/
function setStorage(AddressData storage self, bytes memory key, bytes memory innerKey, address value) internal {
self._storage[key][innerKey] = value;
}
/**
* @dev Get address value from storage
* Retrieves an address value from a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization
* @param innerKey Secondary key for specific relationship
* @return Stored address value, or address(0) if no value has been set
*
* @custom:effects
* - Read-only operation that doesn't modify state
* - Returns default value (address(0)) if entry doesn't exist
* - Used for permission checks and relationship verification
*/
function getStorage(AddressData storage self, bytes memory key, bytes memory innerKey) internal view returns (address) {
return self._storage[key][innerKey];
}
/**
* @dev Delete address value from storage
* Removes an address value from a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization
* @param innerKey Secondary key for specific relationship
*
* @custom:effects
* - Removes value from storage, setting it to default value (address(0))
* - Gas refund is provided when clearing storage to zero
* - Important for revoking permissions or updating relationships
*/
function delStorage(AddressData storage self, bytes memory key, bytes memory innerKey) internal {
delete self._storage[key][innerKey];
}
/**
* @dev Set bytes value in storage
* Assigns a bytes value to a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization (e.g., data type, record ID)
* @param innerKey Secondary key for specific data (e.g., signature, hash)
* @param value Bytes data to store
*
* @custom:effects
* - Updates storage with new bytes data, overwriting any existing value
* - Dynamically sized data is stored with length prefix
* - Gas cost scales with the size of the bytes array
* - Suitable for arbitrary binary data storage
*/
function setStorage(BytesData storage self, bytes memory key, bytes memory innerKey, bytes memory value) internal {
self._storage[key][innerKey] = value;
}
/**
* @dev Get bytes value from storage
* Retrieves a bytes value from a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization
* @param innerKey Secondary key for specific data
* @return Stored bytes value, or empty bytes if no value has been set
*
* @custom:effects
* - Read-only operation that doesn't modify state
* - Returns default value (empty bytes) if entry doesn't exist
* - Gas cost scales with the size of the retrieved data
* - Used for retrieving serialized data, proofs, or signatures
*/
function getStorage(BytesData storage self, bytes memory key, bytes memory innerKey) internal view returns (bytes memory) {
return self._storage[key][innerKey];
}
/**
* @dev Delete bytes value from storage
* Removes a bytes value from a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization
* @param innerKey Secondary key for specific data
*
* @custom:effects
* - Removes value from storage, setting it to default value (empty bytes)
* - Gas refund is provided when clearing storage
* - More gas efficient for larger data due to storage refunds
* - Complete removal of variable-length data
*/
function delStorage(BytesData storage self, bytes memory key, bytes memory innerKey) internal {
delete self._storage[key][innerKey];
}
/**
* @dev Set string value in storage
* Assigns a string value to a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization (e.g., metadata type, record ID)
* @param innerKey Secondary key for specific text (e.g., name, description)
* @param value String data to store
*
* @custom:effects
* - Updates storage with new string, overwriting any existing value
* - Strings are stored as UTF-8 encoded bytes with length prefix
* - Gas cost scales with the length of the string
* - Ideal for human-readable text storage
*/
function setStorage(StringData storage self, bytes memory key, bytes memory innerKey, string memory value) internal {
self._storage[key][innerKey] = value;
}
/**
* @dev Get string value from storage
* Retrieves a string value from a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization
* @param innerKey Secondary key for specific text
* @return Stored string value, or empty string if no value has been set
*
* @custom:effects
* - Read-only operation that doesn't modify state
* - Returns default value (empty string) if entry doesn't exist
* - Gas cost scales with the length of the retrieved string
* - Used for retrieving human-readable configuration and metadata
*/
function getStorage(StringData storage self, bytes memory key, bytes memory innerKey) internal view returns (string memory) {
return self._storage[key][innerKey];
}
/**
* @dev Delete string value from storage
* Removes a string value from a specific key pair in storage
*
* @param self Storage structure reference
* @param key Primary key for categorization
* @param innerKey Secondary key for specific text
*
* @custom:effects
* - Removes value from storage, setting it to default value (empty string)
* - Gas refund is provided when clearing storage
* - More gas efficient for longer strings due to storage refunds
* - Complete removal of variable-length text data
*/
function delStorage(StringData storage self, bytes memory key, bytes memory innerKey) internal {
delete self._storage[key][innerKey];
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {
"contracts/crossApproach/CrossDelegateV6.sol": {
"NFTLibV1": "0x0f0bf93bf16fd28294c637d855fc73b917ef5fcc",
"RapidityLibV4": "0x35b90f99680c426bf6753a78c364b045115cb46e"
}
}
}Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":true,"internalType":"bool","name":"enabled","type":"bool"}],"name":"ConfigAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"bool","name":"enabled","type":"bool"}],"name":"ConfigOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"crossId","type":"uint256"}],"name":"RegisterNftCrossId","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"adminAccount","type":"address"}],"name":"SetAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"srcChainID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"destChainID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"contractFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"agentFee","type":"uint256"}],"name":"SetFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minAmount","type":"uint256"}],"name":"SetMinTokenPairCrossChainAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"contractFee","type":"uint256"}],"name":"SetTokenPairFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"smgID","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"timeStamp","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"WithdrawHistoryFeeLogger","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"collection","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchRegisterNftCrossId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"configAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"configOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"crossId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"crossIdToNftBaseInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentChainID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"key","type":"bytes"},{"internalType":"bytes","name":"innerKey","type":"bytes"}],"name":"delUintValue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256","name":"batchLength","type":"uint256"}],"name":"getBatchFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEtherTransferGasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"srcChainID","type":"uint256"},{"internalType":"uint256","name":"destChainID","type":"uint256"}],"internalType":"struct CrossStorageV2.GetFeesParam","name":"param","type":"tuple"}],"name":"getFee","outputs":[{"components":[{"internalType":"uint256","name":"contractFee","type":"uint256"},{"internalType":"uint256","name":"agentFee","type":"uint256"}],"internalType":"struct CrossStorageV2.GetFeesReturn","name":"fee","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"srcChainID","type":"uint256"},{"internalType":"uint256","name":"destChainID","type":"uint256"}],"internalType":"struct CrossStorageV2.GetFeesParam[]","name":"params","type":"tuple[]"}],"name":"getFees","outputs":[{"components":[{"internalType":"uint256","name":"contractFee","type":"uint256"},{"internalType":"uint256","name":"agentFee","type":"uint256"}],"internalType":"struct CrossStorageV2.GetFeesReturn[]","name":"fees","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxBatchSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenPairID","type":"uint256"}],"name":"getMinTokenPairCrossChainAmount","outputs":[{"internalType":"uint256","name":"minAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getMinTokenPairCrossChainAmountByIndex","outputs":[{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256","name":"minAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMinTokenPairCrossChainAmountLength","outputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPartners","outputs":[{"internalType":"address","name":"tokenManager","type":"address"},{"internalType":"address","name":"smgAdminProxy","type":"address"},{"internalType":"address","name":"smgFeeProxy","type":"address"},{"internalType":"address","name":"quota","type":"address"},{"internalType":"address","name":"sigVerifier","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getStoremanFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenPairID","type":"uint256"}],"name":"getTokenPairFee","outputs":[{"internalType":"uint256","name":"contractFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenPairIDs","type":"uint256[]"}],"name":"getTokenPairFees","outputs":[{"internalType":"uint256[]","name":"contractFees","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"key","type":"bytes"},{"internalType":"bytes","name":"innerKey","type":"bytes"}],"name":"getUintValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"halted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"hashFunc","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hashType","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenPairID","type":"uint256"}],"name":"localTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockedTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nftRegisterCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"adminAccount","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainID","type":"uint256"}],"name":"setChainID","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_etherTransferGasLimit","type":"uint256"}],"name":"setEtherTransferGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"srcChainID","type":"uint256"},{"internalType":"uint256","name":"destChainID","type":"uint256"},{"internalType":"uint256","name":"contractFee","type":"uint256"},{"internalType":"uint256","name":"agentFee","type":"uint256"}],"internalType":"struct CrossStorageV2.SetFeesParam","name":"param","type":"tuple"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"srcChainID","type":"uint256"},{"internalType":"uint256","name":"destChainID","type":"uint256"},{"internalType":"uint256","name":"contractFee","type":"uint256"},{"internalType":"uint256","name":"agentFee","type":"uint256"}],"internalType":"struct CrossStorageV2.SetFeesParam[]","name":"params","type":"tuple[]"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"halt","type":"bool"}],"name":"setHalt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_hashType","type":"uint256"}],"name":"setHashType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxBatchSize","type":"uint256"}],"name":"setMaxBatchSize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256","name":"minAmount","type":"uint256"}],"internalType":"struct CrossDelegateV6.SetMinTokenPairCrossChainAmountParam[]","name":"params","type":"tuple[]"}],"name":"setMinTokenPairCrossChainAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenManager","type":"address"},{"internalType":"address","name":"smgAdminProxy","type":"address"},{"internalType":"address","name":"smgFeeProxy","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"sigVerifier","type":"address"}],"name":"setPartners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256","name":"contractFee","type":"uint256"}],"name":"setTokenPairFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256","name":"contractFee","type":"uint256"}],"internalType":"struct CrossStorageV3.SetTokenPairFeesParam[]","name":"params","type":"tuple[]"}],"name":"setTokenPairFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"key","type":"bytes"},{"internalType":"bytes","name":"innerKey","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setUintValue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"smgFeeReceiverTimeout","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"uniqueID","type":"bytes32"},{"internalType":"bytes32","name":"smgID","type":"bytes32"},{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address","name":"tokenAccount","type":"address"},{"internalType":"address","name":"userAccount","type":"address"},{"internalType":"bytes","name":"r","type":"bytes"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"smgMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"uniqueID","type":"bytes32"},{"internalType":"bytes32","name":"smgID","type":"bytes32"},{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256[]","name":"tokenIDs","type":"uint256[]"},{"internalType":"uint256[]","name":"tokenValues","type":"uint256[]"},{"internalType":"bytes","name":"extData","type":"bytes"},{"internalType":"address","name":"tokenAccount","type":"address"},{"internalType":"address","name":"userAccount","type":"address"},{"internalType":"bytes","name":"r","type":"bytes"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"smgMintNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"uniqueID","type":"bytes32"},{"internalType":"bytes32","name":"smgID","type":"bytes32"},{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address","name":"tokenAccount","type":"address"},{"internalType":"address","name":"userAccount","type":"address"},{"internalType":"bytes","name":"r","type":"bytes"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"smgRelease","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"uniqueID","type":"bytes32"},{"internalType":"bytes32","name":"smgID","type":"bytes32"},{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256[]","name":"tokenIDs","type":"uint256[]"},{"internalType":"uint256[]","name":"tokenValues","type":"uint256[]"},{"internalType":"address","name":"tokenAccount","type":"address"},{"internalType":"address","name":"userAccount","type":"address"},{"internalType":"bytes","name":"r","type":"bytes"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"smgReleaseNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"smgIDs","type":"bytes32[]"}],"name":"smgWithdrawHistoryFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"smgID","type":"bytes32"},{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address","name":"tokenAccount","type":"address"},{"internalType":"bytes","name":"userAccount","type":"bytes"}],"name":"userBurn","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"smgID","type":"bytes32"},{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256[]","name":"tokenIDs","type":"uint256[]"},{"internalType":"uint256[]","name":"tokenValues","type":"uint256[]"},{"internalType":"address","name":"tokenAccount","type":"address"},{"internalType":"bytes","name":"userAccount","type":"bytes"}],"name":"userBurnNFT","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"smgID","type":"bytes32"},{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"userAccount","type":"bytes"}],"name":"userLock","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"smgID","type":"bytes32"},{"internalType":"uint256","name":"tokenPairID","type":"uint256"},{"internalType":"uint256[]","name":"tokenIDs","type":"uint256[]"},{"internalType":"uint256[]","name":"tokenValues","type":"uint256[]"},{"internalType":"bytes","name":"userAccount","type":"bytes"}],"name":"userLockNFT","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040526201fa406011556102586012556014805460ff60a01b1916905534801561002a57600080fd5b506013805433610100026001600160a81b03199091161760011790556153a3806100556000396000f3fe6080604052600436106103b15760003560e01c806373fa58f5116101e7578063bc197c811161010d578063e7c00f6e116100a0578063f23a6e611161006f578063f23a6e6114610c01578063f495438714610c2d578063f851a44014610c4d578063fbc898f414610c6d576103c0565b8063e7c00f6e14610b96578063e92e2c1b14610bab578063ed8d47e614610bc1578063f0baef5214610be1576103c0565b8063d7c985e9116100dc578063d7c985e914610b16578063d8ccfccf14610b2b578063dd27b6cd14610b63578063e02dee8c14610b83576103c0565b8063bc197c8114610a87578063be5212a814610ab6578063d4ee1d9014610ad6578063d52012bc14610af6576103c0565b8063a3d1e38111610185578063b179e1e711610154578063b179e1e714610a1d578063b64ed6db14610a33578063b9b8af0b14610a46578063bbf485ab14610a67576103c0565b8063a3d1e381146109a7578063a6f9dae1146109c7578063a8b38205146109e7578063acf7fff3146109fd576103c0565b80638da5cb5b116101c15780638da5cb5b14610915578063901169161461093a578063926731ea146109675780639472378a14610987576103c0565b806373fa58f5146108c057806379ba5097146108e05780638061babf146108f5576103c0565b8063392a62b9116102d757806354c0de4a1161026a578063704b6c0211610239578063704b6c0214610807578063715018a614610827578063715f250c1461083c57806373e29b0d14610869576103c0565b806354c0de4a146107795780635c60da1b146107995780635dd939ba146107b75780636d70f7ae146107d7576103c0565b80634fb2e45d116102a65780634fb2e45d146106f957806350cc67071461071957806351be6e4914610739578063536686a914610759576103c0565b8063392a62b91461066c57806341ff1bcc1461069957806348d2cb39146106ac5780634cc7125b146106d9576103c0565b80631c40ff211161034f5780632b26a6bf1161031e5780632b26a6bf146105df5780632e96be19146105ff57806333b57a401461061f578063361b31bf1461063f576103c0565b80631c40ff2114610534578063213a25961461056c57806324d7806c1461058c578063257011b6146105cc576103c0565b80630ec61b791161038b5780630ec61b79146104265780630ef2218a1461049a578063150b7a02146104d0578063159982f014610514576103c0565b806301f4d28d146103c85780630a72b1ab146103f05780630d3adbac14610410576103c0565b366103c0576103be610ca2565b005b6103be610ca2565b3480156103d457600080fd5b506103dd610d2c565b6040519081526020015b60405180910390f35b3480156103fc57600080fd5b506103be61040b366004613c77565b610d46565b34801561041c57600080fd5b506103dd601b5481565b34801561043257600080fd5b5061048d610441366004613ce8565b604080518082018252600080825260208083018281528535808452600f835285842096830135808552968352858420548552835260108252848320958352949052919091205490915290565b6040516103e79190613d00565b3480156104a657600080fd5b506103dd6104b5366004613d17565b60208080526000928352604080842090915290825290205481565b3480156104dc57600080fd5b506104fb6104eb366004613e06565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016103e7565b34801561052057600080fd5b506103dd61052f366004613e71565b610e3a565b34801561054057600080fd5b5061055461054f366004613ea5565b610ead565b6040516001600160a01b0390911681526020016103e7565b34801561057857600080fd5b506103be610587366004613f02565b610fee565b34801561059857600080fd5b506105bc6105a7366004613f43565b601c6020526000908152604090205460ff1681565b60405190151581526020016103e7565b6103be6105da366004613fa1565b611144565b3480156105eb57600080fd5b506103be6105fa366004613ea5565b61118a565b34801561060b57600080fd5b506103be61061a366004613ea5565b6111ed565b34801561062b57600080fd5b506103be61063a36600461400f565b611221565b34801561064b57600080fd5b5061065f61065a366004613f02565b6112d3565b6040516103e79190614048565b34801561067857600080fd5b506103dd610687366004613ea5565b60009081526018602052604090205490565b6103be6106a736600461409f565b61144b565b3480156106b857600080fd5b506103dd6106c7366004613f43565b601e6020526000908152604090205481565b3480156106e557600080fd5b506103be6106f436600461411b565b611495565b34801561070557600080fd5b506103be610714366004613f43565b61156e565b34801561072557600080fd5b506103be610734366004614186565b61165a565b34801561074557600080fd5b506103dd610754366004613ea5565b61189e565b34801561076557600080fd5b506103be610774366004614270565b6118b2565b34801561078557600080fd5b506103be6107943660046142a5565b611a2d565b3480156107a557600080fd5b506015546001600160a01b0316610554565b3480156107c357600080fd5b506103be6107d236600461400f565b611b26565b3480156107e357600080fd5b506105bc6107f2366004613f43565b601d6020526000908152604090205460ff1681565b34801561081357600080fd5b506103be610822366004613f43565b611ba9565b34801561083357600080fd5b506103be611c2c565b34801561084857600080fd5b506103dd610857366004613ea5565b6000908152600e602052604090205490565b34801561087557600080fd5b50600a54600b54600c54600954600d54604080516001600160a01b0396871681529486166020860152928516928401929092528316606083015291909116608082015260a0016103e7565b3480156108cc57600080fd5b506103be6108db366004614186565b611c6e565b3480156108ec57600080fd5b506103be611d75565b34801561090157600080fd5b506103dd61091036600461411b565b611db3565b34801561092157600080fd5b506013546105549061010090046001600160a01b031681565b34801561094657600080fd5b5061095a610955366004614270565b611e33565b6040516103e791906142f2565b34801561097357600080fd5b506103be610982366004614305565b611edd565b34801561099357600080fd5b506103be6109a2366004613f02565b611fb2565b3480156109b357600080fd5b506103be6109c2366004614401565b61215d565b3480156109d357600080fd5b506103be6109e2366004613f43565b612285565b3480156109f357600080fd5b506103dd60115481565b348015610a0957600080fd5b506103be610a183660046144d1565b6122d6565b348015610a2957600080fd5b506103dd60165481565b6103be610a41366004614592565b612406565b348015610a5257600080fd5b506014546105bc90600160a01b900460ff1681565b348015610a7357600080fd5b506103be610a8236600461462d565b612457565b348015610a9357600080fd5b506104fb610aa2366004614723565b63bc197c8160e01b98975050505050505050565b348015610ac257600080fd5b506103dd610ad13660046147e1565b61257a565b348015610ae257600080fd5b50601454610554906001600160a01b031681565b348015610b0257600080fd5b506103be610b11366004614803565b61261f565b348015610b2257600080fd5b506103dd61285c565b348015610b3757600080fd5b506103dd610b46366004613d17565b601f60209081526000928352604080842090915290825290205481565b348015610b6f57600080fd5b506103be610b7e366004613ea5565b61286d565b6103be610b91366004614877565b6128d0565b348015610ba257600080fd5b506103dd612b7a565b348015610bb757600080fd5b506103dd60125481565b348015610bcd57600080fd5b506103be610bdc366004613ea5565b612b93565b348015610bed57600080fd5b506103be610bfc3660046147e1565b612c04565b348015610c0d57600080fd5b506104fb610c1c366004614925565b63f23a6e6160e01b95945050505050565b348015610c3957600080fd5b506103be610c4836600461498d565b612ccd565b348015610c5957600080fd5b50601754610554906001600160a01b031681565b348015610c7957600080fd5b50610c8d610c88366004613ea5565b612d1a565b604080519283526020830191909152016103e7565b6015546001600160a01b031680610d005760405162461bcd60e51b815260206004820152601f60248201527f696d706c656d656e746174696f6e20636f6e7472616374206e6f74207365740060448201526064015b60405180910390fd5b60405136600082376000803683855af43d806000843e818015610d21578184f35b8184fd5b5050505050565b6000601a54600003610d3f57506108fc90565b50601a5490565b60135461010090046001600160a01b03163314610d755760405162461bcd60e51b8152600401610cf7906149aa565b6001600160a01b03851615801590610d9557506001600160a01b03841615155b8015610da957506001600160a01b03811615155b610dec5760405162461bcd60e51b815260206004820152601460248201527314185c985b595d195c881a5cc81a5b9d985b1a5960621b6044820152606401610cf7565b600b80546001600160a01b03199081166001600160a01b0396871617909155600a8054821696861696909617909555600c805486169385169390931790925550600d80549093169116179055565b6000601b54600103610e525750805160209091012090565b600282604051610e6291906149f1565b602060405180830381855afa158015610e7f573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610ea29190614a0d565b92915050565b919050565b600a54604051635c83993b60e11b8152600481018390526000916001600160a01b031690829081906060908190859063b907327690602401600060405180830381865afa158015610f02573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f2a9190810190614a6b565b9296509450925090506000849003610f7b5760405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b6044820152606401610cf7565b60008460165403610f935760148301515b9050610fe3565b8360165403610fa6576014820151610f8c565b60405162461bcd60e51b815260206004820152601260248201527124b73b30b634b2103a37b5b2b7103830b4b960711b6044820152606401610cf7565b979650505050505050565b336000908152601d602052604090205460ff168061101b5750336000908152601c602052604090205460ff165b8061103057506017546001600160a01b031633145b8061104a575060135461010090046001600160a01b031633145b6110665760405162461bcd60e51b8152600401610cf790614ad5565b60005b8181101561113f5782828281811061108357611083614afb565b90506040020160200135601860008585858181106110a3576110a3614afb565b905060400201600001358152602001908152602001600020819055508282828181106110d1576110d1614afb565b905060400201600001357fdfa3e1a2556a2caf7af0a1cb98a9eed056ae433c4e109e3398edff9863d45bf584848481811061110e5761110e614afb565b9050604002016020013560405161112791815260200190565b60405180910390a261113881614b27565b9050611069565b505050565b838360006111518361189e565b9050808210156111735760405162461bcd60e51b8152600401610cf790614b40565b6111808888888888612d84565b5050505050505050565b336000908152601c602052604090205460ff16806111b257506017546001600160a01b031633145b806111cc575060135461010090046001600160a01b031633145b6111e85760405162461bcd60e51b8152600401610cf790614b85565b601955565b60135461010090046001600160a01b0316331461121c5760405162461bcd60e51b8152600401610cf7906149aa565b601b55565b336000908152601c602052604090205460ff168061124957506017546001600160a01b031633145b80611263575060135461010090046001600160a01b031633145b61127f5760405162461bcd60e51b8152600401610cf790614b85565b6001600160a01b0382166000818152601d6020526040808220805460ff191685151590811790915590519092917f0ba00283699e8a51615f49e891f96d655cb66dee99cdab7fd2dca130c251818291a35050565b6060816001600160401b038111156112ed576112ed613d43565b60405190808252806020026020018201604052801561133257816020015b604080518082019091526000808252602082015281526020019060019003908161130b5790505b50905060005b8281101561144457600f600085858481811061135657611356614afb565b905060400201600001358152602001908152602001600020600085858481811061138257611382614afb565b905060400201602001358152602001908152602001600020548282815181106113ad576113ad614afb565b602090810291909101015152601060008585848181106113cf576113cf614afb565b90506040020160000135815260200190815260200160002060008585848181106113fb576113fb614afb565b9050604002016020013581526020019081526020016000205482828151811061142657611426614afb565b602090810291909101810151015261143d81614b27565b9050611338565b5092915050565b858560006114588361189e565b90508082101561147a5760405162461bcd60e51b8152600401610cf790614b40565b6114898a8a8a8a8a8a8a612f72565b50505050505050505050565b336000908152601c602052604090205460ff16806114bd57506017546001600160a01b031633145b806114d7575060135461010090046001600160a01b031633145b6114f35760405162461bcd60e51b8152600401610cf790614b85565b611568600085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f890181900481028201810190925287815292508791508690819084018382808284376000920191909152506131c192505050565b50505050565b60135461010090046001600160a01b0316331461159d5760405162461bcd60e51b8152600401610cf7906149aa565b6001600160a01b0381166115f35760405162461bcd60e51b815260206004820152601d60248201527f4e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610cf7565b6013546040516001600160a01b0380841692610100900416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3601380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b601454600160a01b900460ff16156116845760405162461bcd60e51b8152600401610cf790614ba8565b600060606116918b613204565b60408051610100810182528f8152602081018f90529081018d9052606081018c9052608081018b90526001600160a01b03808b1660a083015289811660c0830152600c54939550919350600092909160e083019116156116fc57600c546001600160a01b031661170e565b60135461010090046001600160a01b03165b6001600160a01b0390811690915260408051633c394fd560e21b815260056004820152835160248201526020840151604482015290830151606482015260608301516084820152608083015160a482015260a0830151821660c482015260c0830151821660e482015260e08301519091166101048201529091507335b90f99680c426bf6753a78c364b045115cb46e9063f0e53f5490610124015b60006040518083038186803b1580156117c157600080fd5b505af41580156117d5573d6000803e3d6000fd5b5050505060006118486016548f8e8e8e8e8e604051602001611834979695949392919096875260208701959095526040860193909352606085019190915260808401526001600160a01b0390811660a08401521660c082015260e00190565b604051602081830303815290604052610e3a565b905061188e8482858a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92506132e0915050565b5050505050505050505050505050565b60006118ab6021836133ee565b9392505050565b600c5460009081906001600160a01b0316806118db575060135461010090046001600160a01b03165b6001600160a01b0381166119275760405162461bcd60e51b8152602060048201526013602482015272696e76616c696420736d6746656550726f787960681b6044820152606401610cf7565b60005b84811015611a1457600e600087878481811061194857611948614afb565b9050602002013581526020019081526020016000205492506005600901600087878481811061197957611979614afb565b905060200201358152602001908152602001600020600090556119a5838561340c90919063ffffffff16565b9350816001600160a01b0316428787848181106119c4576119c4614afb565b905060200201357ff12b3f379096849c585fc75843457b18f02c980d39f9462c0ccefc992f2cb87b866040516119fc91815260200190565b60405180910390a4611a0d81614b27565b905061192a565b508215610d2557610d258184611a28610d2c565b613418565b336000908152601d602052604090205460ff1680611a5a5750336000908152601c602052604090205460ff165b80611a6f57506017546001600160a01b031633145b80611a89575060135461010090046001600160a01b031633145b611aa55760405162461bcd60e51b8152600401610cf790614ad5565b80356000818152600f60209081526040808320828601358085529083528184208287013590819055858552601084528285208286528452938290206060870135908190558251948552928401929092529092917f2c40e30353ae48a032fd20f1fece20031c1b80a2bc8512a2c172ff4de2e59519910160405180910390a350565b60135461010090046001600160a01b03163314611b555760405162461bcd60e51b8152600401610cf7906149aa565b6001600160a01b0382166000818152601c6020526040808220805460ff191685151590811790915590519092917fb0952cae2bb8b955d827c964f844b30447210f1f21be8c009772a3044a76534491a35050565b60135461010090046001600160a01b03163314611bd85760405162461bcd60e51b8152600401610cf7906149aa565b601780546001600160a01b0319166001600160a01b0383169081179091556040519081527f5a272403b402d892977df56625f4164ccaf70ca3863991c43ecfe76a6905b0a19060200160405180910390a150565b60135461010090046001600160a01b03163314611c5b5760405162461bcd60e51b8152600401610cf7906149aa565b60138054610100600160a81b0319169055565b601454600160a01b900460ff1615611c985760405162461bcd60e51b8152600401610cf790614ba8565b60006060611ca58b613204565b809250819350505060006040518061012001604052808e81526020018d81526020018c81526020018b81526020018a8152602001611ce1610d2c565b81526001600160a01b03808b1660208301528981166040830152600c546060909201911615611d1b57600c546001600160a01b0316611d2d565b60135461010090046001600160a01b03165b6001600160a01b0316905260405163135122a560e21b81529091507335b90f99680c426bf6753a78c364b045115cb46e90634d448a94906117a9906005908590600401614bdf565b6014546001600160a01b03163303611db157601454601380546001600160a01b0390921661010002610100600160a81b03199092169190911790555b565b6000611e2a600086868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8a01819004810282018101909252888152925088915087908190840183828082843760009201919091525061354292505050565b95945050505050565b6060816001600160401b03811115611e4d57611e4d613d43565b604051908082528060200260200182016040528015611e76578160200160208202803683370190505b50905060005b828110156114445760186000858584818110611e9a57611e9a614afb565b90506020020135815260200190815260200160002054828281518110611ec257611ec2614afb565b6020908102919091010152611ed681614b27565b9050611e7c565b336000908152601c602052604090205460ff1680611f0557506017546001600160a01b031633145b80611f1f575060135461010090046001600160a01b031633145b611f3b5760405162461bcd60e51b8152600401610cf790614b85565b610d25600086868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8a01819004810282018101909252888152925088915087908190840183828082843760009201919091525087925061358a915050565b336000908152601d602052604090205460ff1680611fdf5750336000908152601c602052604090205460ff165b80611ff457506017546001600160a01b031633145b8061200e575060135461010090046001600160a01b031633145b61202a5760405162461bcd60e51b8152600401610cf790614ad5565b60005b8181101561113f57600083838381811061204957612049614afb565b9050604002016020013511156120ab576120a583838381811061206e5761206e614afb565b9050604002016000013584848481811061208a5761208a614afb565b9050604002016020013560216135cf9092919063ffffffff16565b506120d3565b6120d18383838181106120c0576120c0614afb565b6021926040909102013590506135e4565b505b7fdc8a95efff3ce179d1cfc62663ab5898277dcceaf64c7e453f241f4b3dd46eab83838381811061210657612106614afb565b9050604002016000013584848481811061212257612122614afb565b90506040020160200135604051612143929190918252602082015260400190565b60405180910390a18061215581614b27565b91505061202d565b601454600160a01b900460ff16156121875760405162461bcd60e51b8152600401610cf790614ba8565b600060606121948a613204565b6040805160e0810182528e8152602081018e90528082018d9052606081018c9052608081018b90526001600160a01b03808b1660a0830152891660c08201529051630bc60e7f60e21b815292945090925090730f0bf93bf16fd28294c637d855fc73b917ef5fcc90632f1839fc90612213906005908590600401614c6f565b60006040518083038186803b15801561222b57600080fd5b505af415801561223f573d6000803e3d6000fd5b5050505060006122676016548e8d8d8d8d8d6040516020016118349796959493929190614cfe565b905061227684828589896132e0565b50505050505050505050505050565b60135461010090046001600160a01b031633146122b45760405162461bcd60e51b8152600401610cf7906149aa565b601480546001600160a01b0319166001600160a01b0392909216919091179055565b336000908152601c602052604090205460ff16806122fe57506017546001600160a01b031633145b80612318575060135461010090046001600160a01b031633145b6123345760405162461bcd60e51b8152600401610cf790614b85565b80518251146123ab5760405162461bcd60e51b815260206004820152603f60248201527f43726f737344656c656761746556353a20636f6c6c656374696f6e206c656e6760448201527f7468206e6f7420657175616c20746f20746f6b656e496473206c656e677468006064820152608401610cf7565b60005b815181101561113f576123f38382815181106123cc576123cc614afb565b60200260200101518383815181106123e6576123e6614afb565b60200260200101516135f0565b50806123fe81614b27565b9150506123ae565b6124138585858585613708565b600061241e85610ead565b845190915060005b8181101561118057612444838783815181106123e6576123e6614afb565b508061244f81614b27565b915050612426565b601454600160a01b900460ff16156124815760405162461bcd60e51b8152600401610cf790614ba8565b6000606061248e8b613204565b60408051610100810182528f8152602081018f90528082018e9052606081018d9052608081018c905260a081018b90526001600160a01b03808b1660c0830152891660e082015290516343966d8360e11b815292945090925090730f0bf93bf16fd28294c637d855fc73b917ef5fcc9063872cdb0690612515906005908590600401614d89565b60006040518083038186803b15801561252d57600080fd5b505af4158015612541573d6000803e3d6000fd5b50505050600061256b6016548f8e8e8e8e8e8e604051602001611834989796959493929190614e45565b905061188e84828589896132e0565b6000828152601860205260408082205460165491516337e99c6160e21b8152600560048201526024810186905260448101919091526064810191909152608481018390528190730f0bf93bf16fd28294c637d855fc73b917ef5fcc9063dfa671849060a4016040805180830381865af41580156125fb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2a9190614ebc565b336000908152601d602052604090205460ff168061264c5750336000908152601c602052604090205460ff165b8061266157506017546001600160a01b031633145b8061267b575060135461010090046001600160a01b031633145b6126975760405162461bcd60e51b8152600401610cf790614ad5565b60005b8181101561113f578282828181106126b4576126b4614afb565b905060800201604001356005600a0160008585858181106126d7576126d7614afb565b905060800201600001358152602001908152602001600020600085858581811061270357612703614afb565b9050608002016020013581526020019081526020016000208190555082828281811061273157612731614afb565b905060800201606001356005600b01600085858581811061275457612754614afb565b905060800201600001358152602001908152602001600020600085858581811061278057612780614afb565b905060800201602001358152602001908152602001600020819055508282828181106127ae576127ae614afb565b905060800201602001358383838181106127ca576127ca614afb565b905060800201600001357f2c40e30353ae48a032fd20f1fece20031c1b80a2bc8512a2c172ff4de2e5951985858581811061280757612807614afb565b9050608002016040013586868681811061282357612823614afb565b90506080020160600135604051612844929190918252602082015260400190565b60405180910390a361285581614b27565b905061269a565b600061286860216139a2565b905090565b336000908152601c602052604090205460ff168061289557506017546001600160a01b031633145b806128af575060135461010090046001600160a01b031633145b6128cb5760405162461bcd60e51b8152600401610cf790614b85565b601a55565b601454600160a01b900460ff16156128fa5760405162461bcd60e51b8152600401610cf790614ba8565b60135460ff1661291c5760405162461bcd60e51b8152600401610cf790614eea565b6013805460ff19169055600b54604051634af46b4560e11b8152600481018890528791600091829182916001600160a01b03909116906395e8d68a90602401606060405180830381865afa158015612978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299c9190614f32565b9194509250905060ff831660051480156129b65750814210155b80156129c25750804211155b6129de5760405162461bcd60e51b8152600401610cf790614f67565b600088511180156129f757506129f2612b7a565b885111155b612a345760405162461bcd60e51b815260206004820152600e60248201526d092dcecc2d8d2c840d8cadccee8d60931b6044820152606401610cf7565b8651885114612a775760405162461bcd60e51b815260206004820152600f60248201526e098cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610cf7565b60006040518061014001604052808c81526020018b81526020018a81526020018981526020016016548152602001601860008d8152602001908152602001600020548152602001612ac6610d2c565b8152602001886001600160a01b03168152602001878152602001612ae86139ad565b6001600160a01b0316905260405163032a0d7760e11b8152909150730f0bf93bf16fd28294c637d855fc73b917ef5fcc906306541aee90612b30906005908590600401614f90565b60006040518083038186803b158015612b4857600080fd5b505af4158015612b5c573d6000803e3d6000fd5b50506013805460ff1916600117905550505050505050505050505050565b6000601954600003612b8c5750601490565b5060195490565b336000908152601c602052604090205460ff1680612bbb57506017546001600160a01b031633145b80612bd5575060135461010090046001600160a01b031633145b612bf15760405162461bcd60e51b8152600401610cf790614b85565b601654600003612c015760168190555b50565b336000908152601d602052604090205460ff1680612c315750336000908152601c602052604090205460ff165b80612c4657506017546001600160a01b031633145b80612c60575060135461010090046001600160a01b031633145b612c7c5760405162461bcd60e51b8152600401610cf790614ad5565b600082815260186020526040908190208290555182907fdfa3e1a2556a2caf7af0a1cb98a9eed056ae433c4e109e3398edff9863d45bf590612cc19084815260200190565b60405180910390a25050565b60135461010090046001600160a01b03163314612cfc5760405162461bcd60e51b8152600401610cf7906149aa565b60148054911515600160a01b0260ff60a01b19909216919091179055565b6000806000612d2761285c565b9050808410612d6e5760405162461bcd60e51b8152602060048201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152606401610cf7565b612d796021856139e0565b909590945092505050565b601454600160a01b900460ff1615612dae5760405162461bcd60e51b8152600401610cf790614ba8565b60135460ff16612dd05760405162461bcd60e51b8152600401610cf790614eea565b6013805460ff19169055600b54604051634af46b4560e11b8152600481018790528691600091829182916001600160a01b03909116906395e8d68a90602401606060405180830381865afa158015612e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e509190614f32565b9194509250905060ff83166005148015612e6a5750814210155b8015612e765750804211155b612e925760405162461bcd60e51b8152600401610cf790614f67565b6000612e9c6139ad565b905060006040518061010001604052808c81526020018b81526020018a81526020016016548152602001601860008d8152602001908152602001600020548152602001612ee7610d2c565b815260200189898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506001600160a01b038416602090910152604051638fd59dc760e01b81529091507335b90f99680c426bf6753a78c364b045115cb46e90638fd59dc790612b30906005908590600401615065565b601454600160a01b900460ff1615612f9c5760405162461bcd60e51b8152600401610cf790614ba8565b60135460ff16612fbe5760405162461bcd60e51b8152600401610cf790614eea565b6013805460ff19169055600b54604051634af46b4560e11b8152600481018990528891600091829182916001600160a01b03909116906395e8d68a90602401606060405180830381865afa15801561301a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303e9190614f32565b9194509250905060ff831660051480156130585750814210155b80156130645750804211155b6130805760405162461bcd60e51b8152600401610cf790614f67565b600061308a6139ad565b905060006040518061014001604052808e81526020018d81526020018c815260200160165481526020018b8152602001601860008f81526020019081526020016000205481526020016130db610d2c565b81526020018a6001600160a01b0316815260200189898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506001600160a01b0384166020909101526040516301f4bd6760e61b81529091507335b90f99680c426bf6753a78c364b045115cb46e90637d2f59c0906131759060059085906004016150e9565b60006040518083038186803b15801561318d57600080fd5b505af41580156131a1573d6000803e3d6000fd5b50506013805460ff19166001179055505050505050505050505050505050565b60405183906131d19084906149f1565b9081526020016040518091039020816040516131ed91906149f1565b908152602001604051809103902060009055505050565b600b546040516344cefb6960e01b8152600481018390526000916060918391829182916001600160a01b0316906344cefb6990602401600060405180830381865afa158015613257573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261327f9190810190615195565b949e50919c50969a5098509096506005955061329c945050505050565b60ff168360ff161480156132b05750814210155b80156132bc5750804211155b6132d85760405162461bcd60e51b8152600401610cf790614f67565b505050915091565b6020838101516040808601518584015186830151600d548451631161eded60e21b8152600481018d90526024810189905260448101879052606481018590526084810184905260a4810183905260c481018c9052945195969395929491936001600160a01b0390911692634587b7b49260e480820193929182900301816000875af1158015613373573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613397919061525d565b6133e35760405162461bcd60e51b815260206004820152601d60248201527f5369676e617475726520766572696669636174696f6e206661696c65640000006044820152606401610cf7565b505050505050505050565b60008080806133fd86866139ef565b909450925050505b9250929050565b60006118ab828461527a565b814710156134745760405162461bcd60e51b815260206004820152602360248201527f45746865725472616e736665723a20696e73756666696369656e742062616c616044820152626e636560e81b6064820152608401610cf7565b6000836001600160a01b0316838390604051600060405180830381858888f193505050503d80600081146134c4576040519150601f19603f3d011682016040523d82523d6000602084013e6134c9565b606091505b5050905080611568576040805162461bcd60e51b81526020600482015260248101919091527f45746865725472616e736665723a20756e61626c6520746f2073656e6420766160448201527f6c75652c20726563697069656e74206d617920686176652072657665727465646064820152608401610cf7565b6000836000018360405161355691906149f1565b90815260200160405180910390208260405161357291906149f1565b90815260200160405180910390205490509392505050565b80846000018460405161359d91906149f1565b9081526020016040518091039020836040516135b991906149f1565b9081526040519081900360200190205550505050565b60006135dc848484613a29565b949350505050565b60006118ab8383613a46565b6001600160a01b0382166000908152601f602090815260408083208484529091528120541561364357506001600160a01b0382166000908152601f60209081526040808320848452909152902054610ea2565b6001600160a01b0383166000908152601e6020526040812080546001929061366c90849061527a565b90915550506001600160a01b0383166000818152601e602081815260408084208054601f84528286208987528452828620819055868652838052828620908652835281852088905585855292909152905490519092859290917f8c2ba1be01bacbcb1bd736d92a024cc00c86baae1fe782f61581b8824fc3ed199190a4506001600160a01b0382166000908152601e6020526040902054610ea2565b601454600160a01b900460ff16156137325760405162461bcd60e51b8152600401610cf790614ba8565b60135460ff166137545760405162461bcd60e51b8152600401610cf790614eea565b6013805460ff19169055600b54604051634af46b4560e11b8152600481018790528691600091829182916001600160a01b03909116906395e8d68a90602401606060405180830381865afa1580156137b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d49190614f32565b9194509250905060ff831660051480156137ee5750814210155b80156137fa5750804211155b6138165760405162461bcd60e51b8152600401610cf790614f67565b6000875111801561382f575061382a612b7a565b875111155b61386c5760405162461bcd60e51b815260206004820152600e60248201526d092dcecc2d8d2c840d8cadccee8d60931b6044820152606401610cf7565b85518751146138af5760405162461bcd60e51b815260206004820152600f60248201526e098cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610cf7565b60006040518061012001604052808b81526020018a81526020018981526020018881526020016016548152602001601860008c81526020019081526020016000205481526020016138fe610d2c565b81526020018781526020016139116139ad565b6001600160a01b031690526040516322a0e81760e21b8152909150730f0bf93bf16fd28294c637d855fc73b917ef5fcc90638a83a05c9061395990600590859060040161528d565b60006040518083038186803b15801561397157600080fd5b505af4158015613985573d6000803e3d6000fd5b50506013805460ff19166001179055505050505050505050505050565b6000610ea282613a63565b600c546000906001600160a01b031680156139c857806139da565b60135461010090046001600160a01b03165b91505090565b60008080806133fd8686613a6e565b6000818152600283016020526040812054819080613a1e57613a118585613a99565b9250600091506134059050565b600192509050613405565b600082815260028401602052604081208290556135dc8484613aa5565b600081815260028301602052604081208190556118ab8383613ab1565b6000610ea282613abd565b60008080613a7c8585613ac7565b600081815260029690960160205260409095205494959350505050565b60006118ab8383613ad3565b60006118ab8383613aeb565b60006118ab8383613b3a565b6000610ea2825490565b60006118ab8383613c2d565b600081815260018301602052604081205415156118ab565b6000818152600183016020526040812054613b3257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610ea2565b506000610ea2565b60008181526001830160205260408120548015613c23576000613b5e600183615344565b8554909150600090613b7290600190615344565b9050818114613bd7576000866000018281548110613b9257613b92614afb565b9060005260206000200154905080876000018481548110613bb557613bb5614afb565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613be857613be8615357565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610ea2565b6000915050610ea2565b6000826000018281548110613c4457613c44614afb565b9060005260206000200154905092915050565b6001600160a01b0381168114612c0157600080fd5b8035610ea881613c57565b600080600080600060a08688031215613c8f57600080fd5b8535613c9a81613c57565b94506020860135613caa81613c57565b93506040860135613cba81613c57565b92506060860135613cca81613c57565b91506080860135613cda81613c57565b809150509295509295909350565b600060408284031215613cfa57600080fd5b50919050565b815181526020808301519082015260408101610ea2565b60008060408385031215613d2a57600080fd5b8235613d3581613c57565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613d8157613d81613d43565b604052919050565b60006001600160401b03821115613da257613da2613d43565b50601f01601f191660200190565b600082601f830112613dc157600080fd5b8135613dd4613dcf82613d89565b613d59565b818152846020838601011115613de957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613e1c57600080fd5b8435613e2781613c57565b93506020850135613e3781613c57565b92506040850135915060608501356001600160401b03811115613e5957600080fd5b613e6587828801613db0565b91505092959194509250565b600060208284031215613e8357600080fd5b81356001600160401b03811115613e9957600080fd5b6135dc84828501613db0565b600060208284031215613eb757600080fd5b5035919050565b60008083601f840112613ed057600080fd5b5081356001600160401b03811115613ee757600080fd5b6020830191508360208260061b850101111561340557600080fd5b60008060208385031215613f1557600080fd5b82356001600160401b03811115613f2b57600080fd5b613f3785828601613ebe565b90969095509350505050565b600060208284031215613f5557600080fd5b81356118ab81613c57565b60008083601f840112613f7257600080fd5b5081356001600160401b03811115613f8957600080fd5b60208301915083602082850101111561340557600080fd5b600080600080600060808688031215613fb957600080fd5b85359450602086013593506040860135925060608601356001600160401b03811115613fe457600080fd5b613ff088828901613f60565b969995985093965092949392505050565b8015158114612c0157600080fd5b6000806040838503121561402257600080fd5b823561402d81613c57565b9150602083013561403d81614001565b809150509250929050565b602080825282518282018190526000919060409081850190868401855b828110156140925761408284835180518252602090810151910152565b9284019290850190600101614065565b5091979650505050505050565b600080600080600080600060c0888a0312156140ba57600080fd5b8735965060208801359550604088013594506060880135935060808801356140e181613c57565b925060a08801356001600160401b038111156140fc57600080fd5b6141088a828b01613f60565b989b979a50959850939692959293505050565b6000806000806040858703121561413157600080fd5b84356001600160401b038082111561414857600080fd5b61415488838901613f60565b9096509450602087013591508082111561416d57600080fd5b5061417a87828801613f60565b95989497509550505050565b6000806000806000806000806000806101208b8d0312156141a657600080fd5b8a35995060208b0135985060408b0135975060608b0135965060808b0135955060a08b01356141d481613c57565b945060c08b01356141e481613c57565b935060e08b01356001600160401b038111156141ff57600080fd5b61420b8d828e01613f60565b915080945050809250506101008b013590509295989b9194979a5092959850565b60008083601f84011261423e57600080fd5b5081356001600160401b0381111561425557600080fd5b6020830191508360208260051b850101111561340557600080fd5b6000806020838503121561428357600080fd5b82356001600160401b0381111561429957600080fd5b613f378582860161422c565b600060808284031215613cfa57600080fd5b600081518084526020808501945080840160005b838110156142e7578151875295820195908201906001016142cb565b509495945050505050565b6020815260006118ab60208301846142b7565b60008060008060006060868803121561431d57600080fd5b85356001600160401b038082111561433457600080fd5b61434089838a01613f60565b9097509550602088013591508082111561435957600080fd5b5061436688828901613f60565b96999598509660400135949350505050565b60006001600160401b0382111561439157614391613d43565b5060051b60200190565b600082601f8301126143ac57600080fd5b813560206143bc613dcf83614378565b82815260059290921b840181019181810190868411156143db57600080fd5b8286015b848110156143f657803583529183019183016143df565b509695505050505050565b60008060008060008060008060006101208a8c03121561442057600080fd5b8935985060208a0135975060408a0135965060608a01356001600160401b038082111561444c57600080fd5b6144588d838e0161439b565b975060808c013591508082111561446e57600080fd5b61447a8d838e0161439b565b965061448860a08d01613c6c565b955061449660c08d01613c6c565b945060e08c01359150808211156144ac57600080fd5b506144b98c828d01613db0565b9250506101008a013590509295985092959850929598565b600080604083850312156144e457600080fd5b82356001600160401b03808211156144fb57600080fd5b818501915085601f83011261450f57600080fd5b8135602061451f613dcf83614378565b82815260059290921b8401810191818101908984111561453e57600080fd5b948201945b8386101561456557853561455681613c57565b82529482019490820190614543565b9650508601359250508082111561457b57600080fd5b506145888582860161439b565b9150509250929050565b600080600080600060a086880312156145aa57600080fd5b853594506020860135935060408601356001600160401b03808211156145cf57600080fd5b6145db89838a0161439b565b945060608801359150808211156145f157600080fd5b6145fd89838a0161439b565b9350608088013591508082111561461357600080fd5b5061462088828901613db0565b9150509295509295909350565b6000806000806000806000806000806101408b8d03121561464d57600080fd5b8a35995060208b0135985060408b0135975060608b01356001600160401b038082111561467957600080fd5b6146858e838f0161439b565b985060808d013591508082111561469b57600080fd5b6146a78e838f0161439b565b975060a08d01359150808211156146bd57600080fd5b6146c98e838f01613db0565b96506146d760c08e01613c6c565b95506146e560e08e01613c6c565b94506101008d01359150808211156146fc57600080fd5b506147098d828e01613db0565b9250506101208b013590509295989b9194979a5092959850565b60008060008060008060008060a0898b03121561473f57600080fd5b883561474a81613c57565b9750602089013561475a81613c57565b965060408901356001600160401b038082111561477657600080fd5b6147828c838d0161422c565b909850965060608b013591508082111561479b57600080fd5b6147a78c838d0161422c565b909650945060808b01359150808211156147c057600080fd5b506147cd8b828c01613f60565b999c989b5096995094979396929594505050565b600080604083850312156147f457600080fd5b50508035926020909101359150565b6000806020838503121561481657600080fd5b82356001600160401b038082111561482d57600080fd5b818501915085601f83011261484157600080fd5b81358181111561485057600080fd5b8660208260071b850101111561486557600080fd5b60209290920196919550909350505050565b60008060008060008060c0878903121561489057600080fd5b863595506020870135945060408701356001600160401b03808211156148b557600080fd5b6148c18a838b0161439b565b955060608901359150808211156148d757600080fd5b6148e38a838b0161439b565b9450608089013591506148f582613c57565b90925060a0880135908082111561490b57600080fd5b5061491889828a01613db0565b9150509295509295509295565b600080600080600060a0868803121561493d57600080fd5b853561494881613c57565b9450602086013561495881613c57565b9350604086013592506060860135915060808601356001600160401b0381111561498157600080fd5b61462088828901613db0565b60006020828403121561499f57600080fd5b81356118ab81614001565b6020808252600990820152682737ba1037bbb732b960b91b604082015260600190565b60005b838110156149e85781810151838201526020016149d0565b50506000910152565b60008251614a038184602087016149cd565b9190910192915050565b600060208284031215614a1f57600080fd5b5051919050565b600082601f830112614a3757600080fd5b8151614a45613dcf82613d89565b818152846020838601011115614a5a57600080fd5b6135dc8260208301602087016149cd565b60008060008060808587031215614a8157600080fd5b8451935060208501516001600160401b0380821115614a9f57600080fd5b614aab88838901614a26565b9450604087015193506060870151915080821115614ac857600080fd5b50613e6587828801614a26565b6020808252600c908201526b3737ba1037b832b930ba37b960a11b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201614b3957614b39614b11565b5060010190565b60208082526025908201527f43726f737344656c656761746556363a20416d6f756e742062656c6f77206d696040820152646e696d756d60d81b606082015260800190565b6020808252600990820152683737ba1030b236b4b760b91b604082015260600190565b60208082526018908201527f536d61727420636f6e74726163742069732068616c7465640000000000000000604082015260600190565b60006101408201905083825282516020830152602083015160408301526040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160018060a01b0380821660e085015260e08501519150610100818316818601528086015192505050614c676101208401826001600160a01b03169052565b509392505050565b828152604060208201528151604082015260208201516060820152604082015160808201526000606083015160e060a0840152614cb06101208401826142b7565b90506080840151603f198483030160c0850152614ccd82826142b7565b60a08601516001600160a01b0390811660e087015260c0909601519095166101009094019390935250919392505050565b87815286602082015285604082015260e060608201526000614d2360e08301876142b7565b8281036080840152614d3581876142b7565b6001600160a01b0395861660a08501529390941660c090920191909152509695505050505050565b60008151808452614d758160208601602086016149cd565b601f01601f19169290920160200192915050565b82815260406020820152815160408201526020820151606082015260408201516080820152600060608301516101008060a0850152614dcc6101408501836142b7565b91506080850151603f19808685030160c0870152614dea84836142b7565b935060a08701519150808685030160e087015250614e088382614d5d565b92505060c0850151614e24828601826001600160a01b03169052565b505060e08401516001600160a01b0381166101208501525b50949350505050565b60006101008a8352896020840152886040840152806060840152614e6b818401896142b7565b90508281036080840152614e7f81886142b7565b905082810360a0840152614e938187614d5d565b6001600160a01b0395861660c08501529390941660e09092019190915250979650505050505050565b60008060408385031215614ecf57600080fd5b8251614eda81613c57565b6020939093015192949293505050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b805160ff81168114610ea857600080fd5b600080600060608486031215614f4757600080fd5b614f5084614f21565b925060208401519150604084015190509250925092565b6020808252600f908201526e504b206973206e6f7420726561647960881b604082015260600190565b82815260406020820152815160408201526020820151606082015260006040830151610140806080850152614fc96101808501836142b7565b91506060850151603f19808685030160a0870152614fe784836142b7565b9350608087015160c087015260a087015160e087015260c08701519150610100828188015260e0880151925061012061502a818901856001600160a01b03169052565b8189015193508288870301858901526150438685614d5d565b955080890151945050505050614e3c6101608501826001600160a01b03169052565b82815260406020820152815160408201526020820151606082015260408201516080820152606082015160a0820152608082015160c082015260a082015160e0820152600060c08301516101008081850152506150c6610140840182614d5d565b60e094909401516001600160a01b03166101209390930192909252509092915050565b82815260406020820152815160408201526020820151606082015260408201516080820152606082015160a0820152608082015160c082015260a082015160e0820152600060c0830151610100818185015260e08501519150610120615159818601846001600160a01b03169052565b81860151925061014091508182860152615177610180860184614d5d565b908601516001600160a01b0381166101608701529092509050614e3c565b60008060008060008060008060008060006101608c8e0312156151b757600080fd5b8b519a506151c760208d01614f21565b995060408c0151985060608c0151975060808c0151965060a08c0151955060c08c0151945060e08c01516001600160401b0381111561520557600080fd5b6152118e828f01614a26565b9450506101008c01516001600160401b0381111561522e57600080fd5b61523a8e828f01614a26565b9350506101208c015191506101408c015190509295989b509295989b9093969950565b60006020828403121561526f57600080fd5b81516118ab81614001565b80820180821115610ea257610ea2614b11565b828152604060208201528151604082015260208201516060820152600060408301516101208060808501526152c66101608501836142b7565b91506060850151603f19808685030160a08701526152e484836142b7565b9350608087015160c087015260a087015160e087015260c08701519150610100828188015260e088015192508187860301848801526153238584614d5d565b9450808801519350505050614e3c6101408501826001600160a01b03169052565b81810381811115610ea257610ea2614b11565b634e487b7160e01b600052603160045260246000fdfea26469706673582212203694dd0e35297d9fe4b48651c4eb4b1dc0c416ecd2618e26f10a2f3ad64c170d64736f6c63430008120033
Deployed Bytecode
0x6080604052600436106103b15760003560e01c806373fa58f5116101e7578063bc197c811161010d578063e7c00f6e116100a0578063f23a6e611161006f578063f23a6e6114610c01578063f495438714610c2d578063f851a44014610c4d578063fbc898f414610c6d576103c0565b8063e7c00f6e14610b96578063e92e2c1b14610bab578063ed8d47e614610bc1578063f0baef5214610be1576103c0565b8063d7c985e9116100dc578063d7c985e914610b16578063d8ccfccf14610b2b578063dd27b6cd14610b63578063e02dee8c14610b83576103c0565b8063bc197c8114610a87578063be5212a814610ab6578063d4ee1d9014610ad6578063d52012bc14610af6576103c0565b8063a3d1e38111610185578063b179e1e711610154578063b179e1e714610a1d578063b64ed6db14610a33578063b9b8af0b14610a46578063bbf485ab14610a67576103c0565b8063a3d1e381146109a7578063a6f9dae1146109c7578063a8b38205146109e7578063acf7fff3146109fd576103c0565b80638da5cb5b116101c15780638da5cb5b14610915578063901169161461093a578063926731ea146109675780639472378a14610987576103c0565b806373fa58f5146108c057806379ba5097146108e05780638061babf146108f5576103c0565b8063392a62b9116102d757806354c0de4a1161026a578063704b6c0211610239578063704b6c0214610807578063715018a614610827578063715f250c1461083c57806373e29b0d14610869576103c0565b806354c0de4a146107795780635c60da1b146107995780635dd939ba146107b75780636d70f7ae146107d7576103c0565b80634fb2e45d116102a65780634fb2e45d146106f957806350cc67071461071957806351be6e4914610739578063536686a914610759576103c0565b8063392a62b91461066c57806341ff1bcc1461069957806348d2cb39146106ac5780634cc7125b146106d9576103c0565b80631c40ff211161034f5780632b26a6bf1161031e5780632b26a6bf146105df5780632e96be19146105ff57806333b57a401461061f578063361b31bf1461063f576103c0565b80631c40ff2114610534578063213a25961461056c57806324d7806c1461058c578063257011b6146105cc576103c0565b80630ec61b791161038b5780630ec61b79146104265780630ef2218a1461049a578063150b7a02146104d0578063159982f014610514576103c0565b806301f4d28d146103c85780630a72b1ab146103f05780630d3adbac14610410576103c0565b366103c0576103be610ca2565b005b6103be610ca2565b3480156103d457600080fd5b506103dd610d2c565b6040519081526020015b60405180910390f35b3480156103fc57600080fd5b506103be61040b366004613c77565b610d46565b34801561041c57600080fd5b506103dd601b5481565b34801561043257600080fd5b5061048d610441366004613ce8565b604080518082018252600080825260208083018281528535808452600f835285842096830135808552968352858420548552835260108252848320958352949052919091205490915290565b6040516103e79190613d00565b3480156104a657600080fd5b506103dd6104b5366004613d17565b60208080526000928352604080842090915290825290205481565b3480156104dc57600080fd5b506104fb6104eb366004613e06565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016103e7565b34801561052057600080fd5b506103dd61052f366004613e71565b610e3a565b34801561054057600080fd5b5061055461054f366004613ea5565b610ead565b6040516001600160a01b0390911681526020016103e7565b34801561057857600080fd5b506103be610587366004613f02565b610fee565b34801561059857600080fd5b506105bc6105a7366004613f43565b601c6020526000908152604090205460ff1681565b60405190151581526020016103e7565b6103be6105da366004613fa1565b611144565b3480156105eb57600080fd5b506103be6105fa366004613ea5565b61118a565b34801561060b57600080fd5b506103be61061a366004613ea5565b6111ed565b34801561062b57600080fd5b506103be61063a36600461400f565b611221565b34801561064b57600080fd5b5061065f61065a366004613f02565b6112d3565b6040516103e79190614048565b34801561067857600080fd5b506103dd610687366004613ea5565b60009081526018602052604090205490565b6103be6106a736600461409f565b61144b565b3480156106b857600080fd5b506103dd6106c7366004613f43565b601e6020526000908152604090205481565b3480156106e557600080fd5b506103be6106f436600461411b565b611495565b34801561070557600080fd5b506103be610714366004613f43565b61156e565b34801561072557600080fd5b506103be610734366004614186565b61165a565b34801561074557600080fd5b506103dd610754366004613ea5565b61189e565b34801561076557600080fd5b506103be610774366004614270565b6118b2565b34801561078557600080fd5b506103be6107943660046142a5565b611a2d565b3480156107a557600080fd5b506015546001600160a01b0316610554565b3480156107c357600080fd5b506103be6107d236600461400f565b611b26565b3480156107e357600080fd5b506105bc6107f2366004613f43565b601d6020526000908152604090205460ff1681565b34801561081357600080fd5b506103be610822366004613f43565b611ba9565b34801561083357600080fd5b506103be611c2c565b34801561084857600080fd5b506103dd610857366004613ea5565b6000908152600e602052604090205490565b34801561087557600080fd5b50600a54600b54600c54600954600d54604080516001600160a01b0396871681529486166020860152928516928401929092528316606083015291909116608082015260a0016103e7565b3480156108cc57600080fd5b506103be6108db366004614186565b611c6e565b3480156108ec57600080fd5b506103be611d75565b34801561090157600080fd5b506103dd61091036600461411b565b611db3565b34801561092157600080fd5b506013546105549061010090046001600160a01b031681565b34801561094657600080fd5b5061095a610955366004614270565b611e33565b6040516103e791906142f2565b34801561097357600080fd5b506103be610982366004614305565b611edd565b34801561099357600080fd5b506103be6109a2366004613f02565b611fb2565b3480156109b357600080fd5b506103be6109c2366004614401565b61215d565b3480156109d357600080fd5b506103be6109e2366004613f43565b612285565b3480156109f357600080fd5b506103dd60115481565b348015610a0957600080fd5b506103be610a183660046144d1565b6122d6565b348015610a2957600080fd5b506103dd60165481565b6103be610a41366004614592565b612406565b348015610a5257600080fd5b506014546105bc90600160a01b900460ff1681565b348015610a7357600080fd5b506103be610a8236600461462d565b612457565b348015610a9357600080fd5b506104fb610aa2366004614723565b63bc197c8160e01b98975050505050505050565b348015610ac257600080fd5b506103dd610ad13660046147e1565b61257a565b348015610ae257600080fd5b50601454610554906001600160a01b031681565b348015610b0257600080fd5b506103be610b11366004614803565b61261f565b348015610b2257600080fd5b506103dd61285c565b348015610b3757600080fd5b506103dd610b46366004613d17565b601f60209081526000928352604080842090915290825290205481565b348015610b6f57600080fd5b506103be610b7e366004613ea5565b61286d565b6103be610b91366004614877565b6128d0565b348015610ba257600080fd5b506103dd612b7a565b348015610bb757600080fd5b506103dd60125481565b348015610bcd57600080fd5b506103be610bdc366004613ea5565b612b93565b348015610bed57600080fd5b506103be610bfc3660046147e1565b612c04565b348015610c0d57600080fd5b506104fb610c1c366004614925565b63f23a6e6160e01b95945050505050565b348015610c3957600080fd5b506103be610c4836600461498d565b612ccd565b348015610c5957600080fd5b50601754610554906001600160a01b031681565b348015610c7957600080fd5b50610c8d610c88366004613ea5565b612d1a565b604080519283526020830191909152016103e7565b6015546001600160a01b031680610d005760405162461bcd60e51b815260206004820152601f60248201527f696d706c656d656e746174696f6e20636f6e7472616374206e6f74207365740060448201526064015b60405180910390fd5b60405136600082376000803683855af43d806000843e818015610d21578184f35b8184fd5b5050505050565b6000601a54600003610d3f57506108fc90565b50601a5490565b60135461010090046001600160a01b03163314610d755760405162461bcd60e51b8152600401610cf7906149aa565b6001600160a01b03851615801590610d9557506001600160a01b03841615155b8015610da957506001600160a01b03811615155b610dec5760405162461bcd60e51b815260206004820152601460248201527314185c985b595d195c881a5cc81a5b9d985b1a5960621b6044820152606401610cf7565b600b80546001600160a01b03199081166001600160a01b0396871617909155600a8054821696861696909617909555600c805486169385169390931790925550600d80549093169116179055565b6000601b54600103610e525750805160209091012090565b600282604051610e6291906149f1565b602060405180830381855afa158015610e7f573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610ea29190614a0d565b92915050565b919050565b600a54604051635c83993b60e11b8152600481018390526000916001600160a01b031690829081906060908190859063b907327690602401600060405180830381865afa158015610f02573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f2a9190810190614a6b565b9296509450925090506000849003610f7b5760405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b6044820152606401610cf7565b60008460165403610f935760148301515b9050610fe3565b8360165403610fa6576014820151610f8c565b60405162461bcd60e51b815260206004820152601260248201527124b73b30b634b2103a37b5b2b7103830b4b960711b6044820152606401610cf7565b979650505050505050565b336000908152601d602052604090205460ff168061101b5750336000908152601c602052604090205460ff165b8061103057506017546001600160a01b031633145b8061104a575060135461010090046001600160a01b031633145b6110665760405162461bcd60e51b8152600401610cf790614ad5565b60005b8181101561113f5782828281811061108357611083614afb565b90506040020160200135601860008585858181106110a3576110a3614afb565b905060400201600001358152602001908152602001600020819055508282828181106110d1576110d1614afb565b905060400201600001357fdfa3e1a2556a2caf7af0a1cb98a9eed056ae433c4e109e3398edff9863d45bf584848481811061110e5761110e614afb565b9050604002016020013560405161112791815260200190565b60405180910390a261113881614b27565b9050611069565b505050565b838360006111518361189e565b9050808210156111735760405162461bcd60e51b8152600401610cf790614b40565b6111808888888888612d84565b5050505050505050565b336000908152601c602052604090205460ff16806111b257506017546001600160a01b031633145b806111cc575060135461010090046001600160a01b031633145b6111e85760405162461bcd60e51b8152600401610cf790614b85565b601955565b60135461010090046001600160a01b0316331461121c5760405162461bcd60e51b8152600401610cf7906149aa565b601b55565b336000908152601c602052604090205460ff168061124957506017546001600160a01b031633145b80611263575060135461010090046001600160a01b031633145b61127f5760405162461bcd60e51b8152600401610cf790614b85565b6001600160a01b0382166000818152601d6020526040808220805460ff191685151590811790915590519092917f0ba00283699e8a51615f49e891f96d655cb66dee99cdab7fd2dca130c251818291a35050565b6060816001600160401b038111156112ed576112ed613d43565b60405190808252806020026020018201604052801561133257816020015b604080518082019091526000808252602082015281526020019060019003908161130b5790505b50905060005b8281101561144457600f600085858481811061135657611356614afb565b905060400201600001358152602001908152602001600020600085858481811061138257611382614afb565b905060400201602001358152602001908152602001600020548282815181106113ad576113ad614afb565b602090810291909101015152601060008585848181106113cf576113cf614afb565b90506040020160000135815260200190815260200160002060008585848181106113fb576113fb614afb565b9050604002016020013581526020019081526020016000205482828151811061142657611426614afb565b602090810291909101810151015261143d81614b27565b9050611338565b5092915050565b858560006114588361189e565b90508082101561147a5760405162461bcd60e51b8152600401610cf790614b40565b6114898a8a8a8a8a8a8a612f72565b50505050505050505050565b336000908152601c602052604090205460ff16806114bd57506017546001600160a01b031633145b806114d7575060135461010090046001600160a01b031633145b6114f35760405162461bcd60e51b8152600401610cf790614b85565b611568600085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f890181900481028201810190925287815292508791508690819084018382808284376000920191909152506131c192505050565b50505050565b60135461010090046001600160a01b0316331461159d5760405162461bcd60e51b8152600401610cf7906149aa565b6001600160a01b0381166115f35760405162461bcd60e51b815260206004820152601d60248201527f4e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610cf7565b6013546040516001600160a01b0380841692610100900416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3601380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b601454600160a01b900460ff16156116845760405162461bcd60e51b8152600401610cf790614ba8565b600060606116918b613204565b60408051610100810182528f8152602081018f90529081018d9052606081018c9052608081018b90526001600160a01b03808b1660a083015289811660c0830152600c54939550919350600092909160e083019116156116fc57600c546001600160a01b031661170e565b60135461010090046001600160a01b03165b6001600160a01b0390811690915260408051633c394fd560e21b815260056004820152835160248201526020840151604482015290830151606482015260608301516084820152608083015160a482015260a0830151821660c482015260c0830151821660e482015260e08301519091166101048201529091507335b90f99680c426bf6753a78c364b045115cb46e9063f0e53f5490610124015b60006040518083038186803b1580156117c157600080fd5b505af41580156117d5573d6000803e3d6000fd5b5050505060006118486016548f8e8e8e8e8e604051602001611834979695949392919096875260208701959095526040860193909352606085019190915260808401526001600160a01b0390811660a08401521660c082015260e00190565b604051602081830303815290604052610e3a565b905061188e8482858a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92506132e0915050565b5050505050505050505050505050565b60006118ab6021836133ee565b9392505050565b600c5460009081906001600160a01b0316806118db575060135461010090046001600160a01b03165b6001600160a01b0381166119275760405162461bcd60e51b8152602060048201526013602482015272696e76616c696420736d6746656550726f787960681b6044820152606401610cf7565b60005b84811015611a1457600e600087878481811061194857611948614afb565b9050602002013581526020019081526020016000205492506005600901600087878481811061197957611979614afb565b905060200201358152602001908152602001600020600090556119a5838561340c90919063ffffffff16565b9350816001600160a01b0316428787848181106119c4576119c4614afb565b905060200201357ff12b3f379096849c585fc75843457b18f02c980d39f9462c0ccefc992f2cb87b866040516119fc91815260200190565b60405180910390a4611a0d81614b27565b905061192a565b508215610d2557610d258184611a28610d2c565b613418565b336000908152601d602052604090205460ff1680611a5a5750336000908152601c602052604090205460ff165b80611a6f57506017546001600160a01b031633145b80611a89575060135461010090046001600160a01b031633145b611aa55760405162461bcd60e51b8152600401610cf790614ad5565b80356000818152600f60209081526040808320828601358085529083528184208287013590819055858552601084528285208286528452938290206060870135908190558251948552928401929092529092917f2c40e30353ae48a032fd20f1fece20031c1b80a2bc8512a2c172ff4de2e59519910160405180910390a350565b60135461010090046001600160a01b03163314611b555760405162461bcd60e51b8152600401610cf7906149aa565b6001600160a01b0382166000818152601c6020526040808220805460ff191685151590811790915590519092917fb0952cae2bb8b955d827c964f844b30447210f1f21be8c009772a3044a76534491a35050565b60135461010090046001600160a01b03163314611bd85760405162461bcd60e51b8152600401610cf7906149aa565b601780546001600160a01b0319166001600160a01b0383169081179091556040519081527f5a272403b402d892977df56625f4164ccaf70ca3863991c43ecfe76a6905b0a19060200160405180910390a150565b60135461010090046001600160a01b03163314611c5b5760405162461bcd60e51b8152600401610cf7906149aa565b60138054610100600160a81b0319169055565b601454600160a01b900460ff1615611c985760405162461bcd60e51b8152600401610cf790614ba8565b60006060611ca58b613204565b809250819350505060006040518061012001604052808e81526020018d81526020018c81526020018b81526020018a8152602001611ce1610d2c565b81526001600160a01b03808b1660208301528981166040830152600c546060909201911615611d1b57600c546001600160a01b0316611d2d565b60135461010090046001600160a01b03165b6001600160a01b0316905260405163135122a560e21b81529091507335b90f99680c426bf6753a78c364b045115cb46e90634d448a94906117a9906005908590600401614bdf565b6014546001600160a01b03163303611db157601454601380546001600160a01b0390921661010002610100600160a81b03199092169190911790555b565b6000611e2a600086868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8a01819004810282018101909252888152925088915087908190840183828082843760009201919091525061354292505050565b95945050505050565b6060816001600160401b03811115611e4d57611e4d613d43565b604051908082528060200260200182016040528015611e76578160200160208202803683370190505b50905060005b828110156114445760186000858584818110611e9a57611e9a614afb565b90506020020135815260200190815260200160002054828281518110611ec257611ec2614afb565b6020908102919091010152611ed681614b27565b9050611e7c565b336000908152601c602052604090205460ff1680611f0557506017546001600160a01b031633145b80611f1f575060135461010090046001600160a01b031633145b611f3b5760405162461bcd60e51b8152600401610cf790614b85565b610d25600086868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8a01819004810282018101909252888152925088915087908190840183828082843760009201919091525087925061358a915050565b336000908152601d602052604090205460ff1680611fdf5750336000908152601c602052604090205460ff165b80611ff457506017546001600160a01b031633145b8061200e575060135461010090046001600160a01b031633145b61202a5760405162461bcd60e51b8152600401610cf790614ad5565b60005b8181101561113f57600083838381811061204957612049614afb565b9050604002016020013511156120ab576120a583838381811061206e5761206e614afb565b9050604002016000013584848481811061208a5761208a614afb565b9050604002016020013560216135cf9092919063ffffffff16565b506120d3565b6120d18383838181106120c0576120c0614afb565b6021926040909102013590506135e4565b505b7fdc8a95efff3ce179d1cfc62663ab5898277dcceaf64c7e453f241f4b3dd46eab83838381811061210657612106614afb565b9050604002016000013584848481811061212257612122614afb565b90506040020160200135604051612143929190918252602082015260400190565b60405180910390a18061215581614b27565b91505061202d565b601454600160a01b900460ff16156121875760405162461bcd60e51b8152600401610cf790614ba8565b600060606121948a613204565b6040805160e0810182528e8152602081018e90528082018d9052606081018c9052608081018b90526001600160a01b03808b1660a0830152891660c08201529051630bc60e7f60e21b815292945090925090730f0bf93bf16fd28294c637d855fc73b917ef5fcc90632f1839fc90612213906005908590600401614c6f565b60006040518083038186803b15801561222b57600080fd5b505af415801561223f573d6000803e3d6000fd5b5050505060006122676016548e8d8d8d8d8d6040516020016118349796959493929190614cfe565b905061227684828589896132e0565b50505050505050505050505050565b60135461010090046001600160a01b031633146122b45760405162461bcd60e51b8152600401610cf7906149aa565b601480546001600160a01b0319166001600160a01b0392909216919091179055565b336000908152601c602052604090205460ff16806122fe57506017546001600160a01b031633145b80612318575060135461010090046001600160a01b031633145b6123345760405162461bcd60e51b8152600401610cf790614b85565b80518251146123ab5760405162461bcd60e51b815260206004820152603f60248201527f43726f737344656c656761746556353a20636f6c6c656374696f6e206c656e6760448201527f7468206e6f7420657175616c20746f20746f6b656e496473206c656e677468006064820152608401610cf7565b60005b815181101561113f576123f38382815181106123cc576123cc614afb565b60200260200101518383815181106123e6576123e6614afb565b60200260200101516135f0565b50806123fe81614b27565b9150506123ae565b6124138585858585613708565b600061241e85610ead565b845190915060005b8181101561118057612444838783815181106123e6576123e6614afb565b508061244f81614b27565b915050612426565b601454600160a01b900460ff16156124815760405162461bcd60e51b8152600401610cf790614ba8565b6000606061248e8b613204565b60408051610100810182528f8152602081018f90528082018e9052606081018d9052608081018c905260a081018b90526001600160a01b03808b1660c0830152891660e082015290516343966d8360e11b815292945090925090730f0bf93bf16fd28294c637d855fc73b917ef5fcc9063872cdb0690612515906005908590600401614d89565b60006040518083038186803b15801561252d57600080fd5b505af4158015612541573d6000803e3d6000fd5b50505050600061256b6016548f8e8e8e8e8e8e604051602001611834989796959493929190614e45565b905061188e84828589896132e0565b6000828152601860205260408082205460165491516337e99c6160e21b8152600560048201526024810186905260448101919091526064810191909152608481018390528190730f0bf93bf16fd28294c637d855fc73b917ef5fcc9063dfa671849060a4016040805180830381865af41580156125fb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2a9190614ebc565b336000908152601d602052604090205460ff168061264c5750336000908152601c602052604090205460ff165b8061266157506017546001600160a01b031633145b8061267b575060135461010090046001600160a01b031633145b6126975760405162461bcd60e51b8152600401610cf790614ad5565b60005b8181101561113f578282828181106126b4576126b4614afb565b905060800201604001356005600a0160008585858181106126d7576126d7614afb565b905060800201600001358152602001908152602001600020600085858581811061270357612703614afb565b9050608002016020013581526020019081526020016000208190555082828281811061273157612731614afb565b905060800201606001356005600b01600085858581811061275457612754614afb565b905060800201600001358152602001908152602001600020600085858581811061278057612780614afb565b905060800201602001358152602001908152602001600020819055508282828181106127ae576127ae614afb565b905060800201602001358383838181106127ca576127ca614afb565b905060800201600001357f2c40e30353ae48a032fd20f1fece20031c1b80a2bc8512a2c172ff4de2e5951985858581811061280757612807614afb565b9050608002016040013586868681811061282357612823614afb565b90506080020160600135604051612844929190918252602082015260400190565b60405180910390a361285581614b27565b905061269a565b600061286860216139a2565b905090565b336000908152601c602052604090205460ff168061289557506017546001600160a01b031633145b806128af575060135461010090046001600160a01b031633145b6128cb5760405162461bcd60e51b8152600401610cf790614b85565b601a55565b601454600160a01b900460ff16156128fa5760405162461bcd60e51b8152600401610cf790614ba8565b60135460ff1661291c5760405162461bcd60e51b8152600401610cf790614eea565b6013805460ff19169055600b54604051634af46b4560e11b8152600481018890528791600091829182916001600160a01b03909116906395e8d68a90602401606060405180830381865afa158015612978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299c9190614f32565b9194509250905060ff831660051480156129b65750814210155b80156129c25750804211155b6129de5760405162461bcd60e51b8152600401610cf790614f67565b600088511180156129f757506129f2612b7a565b885111155b612a345760405162461bcd60e51b815260206004820152600e60248201526d092dcecc2d8d2c840d8cadccee8d60931b6044820152606401610cf7565b8651885114612a775760405162461bcd60e51b815260206004820152600f60248201526e098cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610cf7565b60006040518061014001604052808c81526020018b81526020018a81526020018981526020016016548152602001601860008d8152602001908152602001600020548152602001612ac6610d2c565b8152602001886001600160a01b03168152602001878152602001612ae86139ad565b6001600160a01b0316905260405163032a0d7760e11b8152909150730f0bf93bf16fd28294c637d855fc73b917ef5fcc906306541aee90612b30906005908590600401614f90565b60006040518083038186803b158015612b4857600080fd5b505af4158015612b5c573d6000803e3d6000fd5b50506013805460ff1916600117905550505050505050505050505050565b6000601954600003612b8c5750601490565b5060195490565b336000908152601c602052604090205460ff1680612bbb57506017546001600160a01b031633145b80612bd5575060135461010090046001600160a01b031633145b612bf15760405162461bcd60e51b8152600401610cf790614b85565b601654600003612c015760168190555b50565b336000908152601d602052604090205460ff1680612c315750336000908152601c602052604090205460ff165b80612c4657506017546001600160a01b031633145b80612c60575060135461010090046001600160a01b031633145b612c7c5760405162461bcd60e51b8152600401610cf790614ad5565b600082815260186020526040908190208290555182907fdfa3e1a2556a2caf7af0a1cb98a9eed056ae433c4e109e3398edff9863d45bf590612cc19084815260200190565b60405180910390a25050565b60135461010090046001600160a01b03163314612cfc5760405162461bcd60e51b8152600401610cf7906149aa565b60148054911515600160a01b0260ff60a01b19909216919091179055565b6000806000612d2761285c565b9050808410612d6e5760405162461bcd60e51b8152602060048201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152606401610cf7565b612d796021856139e0565b909590945092505050565b601454600160a01b900460ff1615612dae5760405162461bcd60e51b8152600401610cf790614ba8565b60135460ff16612dd05760405162461bcd60e51b8152600401610cf790614eea565b6013805460ff19169055600b54604051634af46b4560e11b8152600481018790528691600091829182916001600160a01b03909116906395e8d68a90602401606060405180830381865afa158015612e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e509190614f32565b9194509250905060ff83166005148015612e6a5750814210155b8015612e765750804211155b612e925760405162461bcd60e51b8152600401610cf790614f67565b6000612e9c6139ad565b905060006040518061010001604052808c81526020018b81526020018a81526020016016548152602001601860008d8152602001908152602001600020548152602001612ee7610d2c565b815260200189898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506001600160a01b038416602090910152604051638fd59dc760e01b81529091507335b90f99680c426bf6753a78c364b045115cb46e90638fd59dc790612b30906005908590600401615065565b601454600160a01b900460ff1615612f9c5760405162461bcd60e51b8152600401610cf790614ba8565b60135460ff16612fbe5760405162461bcd60e51b8152600401610cf790614eea565b6013805460ff19169055600b54604051634af46b4560e11b8152600481018990528891600091829182916001600160a01b03909116906395e8d68a90602401606060405180830381865afa15801561301a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303e9190614f32565b9194509250905060ff831660051480156130585750814210155b80156130645750804211155b6130805760405162461bcd60e51b8152600401610cf790614f67565b600061308a6139ad565b905060006040518061014001604052808e81526020018d81526020018c815260200160165481526020018b8152602001601860008f81526020019081526020016000205481526020016130db610d2c565b81526020018a6001600160a01b0316815260200189898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506001600160a01b0384166020909101526040516301f4bd6760e61b81529091507335b90f99680c426bf6753a78c364b045115cb46e90637d2f59c0906131759060059085906004016150e9565b60006040518083038186803b15801561318d57600080fd5b505af41580156131a1573d6000803e3d6000fd5b50506013805460ff19166001179055505050505050505050505050505050565b60405183906131d19084906149f1565b9081526020016040518091039020816040516131ed91906149f1565b908152602001604051809103902060009055505050565b600b546040516344cefb6960e01b8152600481018390526000916060918391829182916001600160a01b0316906344cefb6990602401600060405180830381865afa158015613257573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261327f9190810190615195565b949e50919c50969a5098509096506005955061329c945050505050565b60ff168360ff161480156132b05750814210155b80156132bc5750804211155b6132d85760405162461bcd60e51b8152600401610cf790614f67565b505050915091565b6020838101516040808601518584015186830151600d548451631161eded60e21b8152600481018d90526024810189905260448101879052606481018590526084810184905260a4810183905260c481018c9052945195969395929491936001600160a01b0390911692634587b7b49260e480820193929182900301816000875af1158015613373573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613397919061525d565b6133e35760405162461bcd60e51b815260206004820152601d60248201527f5369676e617475726520766572696669636174696f6e206661696c65640000006044820152606401610cf7565b505050505050505050565b60008080806133fd86866139ef565b909450925050505b9250929050565b60006118ab828461527a565b814710156134745760405162461bcd60e51b815260206004820152602360248201527f45746865725472616e736665723a20696e73756666696369656e742062616c616044820152626e636560e81b6064820152608401610cf7565b6000836001600160a01b0316838390604051600060405180830381858888f193505050503d80600081146134c4576040519150601f19603f3d011682016040523d82523d6000602084013e6134c9565b606091505b5050905080611568576040805162461bcd60e51b81526020600482015260248101919091527f45746865725472616e736665723a20756e61626c6520746f2073656e6420766160448201527f6c75652c20726563697069656e74206d617920686176652072657665727465646064820152608401610cf7565b6000836000018360405161355691906149f1565b90815260200160405180910390208260405161357291906149f1565b90815260200160405180910390205490509392505050565b80846000018460405161359d91906149f1565b9081526020016040518091039020836040516135b991906149f1565b9081526040519081900360200190205550505050565b60006135dc848484613a29565b949350505050565b60006118ab8383613a46565b6001600160a01b0382166000908152601f602090815260408083208484529091528120541561364357506001600160a01b0382166000908152601f60209081526040808320848452909152902054610ea2565b6001600160a01b0383166000908152601e6020526040812080546001929061366c90849061527a565b90915550506001600160a01b0383166000818152601e602081815260408084208054601f84528286208987528452828620819055868652838052828620908652835281852088905585855292909152905490519092859290917f8c2ba1be01bacbcb1bd736d92a024cc00c86baae1fe782f61581b8824fc3ed199190a4506001600160a01b0382166000908152601e6020526040902054610ea2565b601454600160a01b900460ff16156137325760405162461bcd60e51b8152600401610cf790614ba8565b60135460ff166137545760405162461bcd60e51b8152600401610cf790614eea565b6013805460ff19169055600b54604051634af46b4560e11b8152600481018790528691600091829182916001600160a01b03909116906395e8d68a90602401606060405180830381865afa1580156137b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d49190614f32565b9194509250905060ff831660051480156137ee5750814210155b80156137fa5750804211155b6138165760405162461bcd60e51b8152600401610cf790614f67565b6000875111801561382f575061382a612b7a565b875111155b61386c5760405162461bcd60e51b815260206004820152600e60248201526d092dcecc2d8d2c840d8cadccee8d60931b6044820152606401610cf7565b85518751146138af5760405162461bcd60e51b815260206004820152600f60248201526e098cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401610cf7565b60006040518061012001604052808b81526020018a81526020018981526020018881526020016016548152602001601860008c81526020019081526020016000205481526020016138fe610d2c565b81526020018781526020016139116139ad565b6001600160a01b031690526040516322a0e81760e21b8152909150730f0bf93bf16fd28294c637d855fc73b917ef5fcc90638a83a05c9061395990600590859060040161528d565b60006040518083038186803b15801561397157600080fd5b505af4158015613985573d6000803e3d6000fd5b50506013805460ff19166001179055505050505050505050505050565b6000610ea282613a63565b600c546000906001600160a01b031680156139c857806139da565b60135461010090046001600160a01b03165b91505090565b60008080806133fd8686613a6e565b6000818152600283016020526040812054819080613a1e57613a118585613a99565b9250600091506134059050565b600192509050613405565b600082815260028401602052604081208290556135dc8484613aa5565b600081815260028301602052604081208190556118ab8383613ab1565b6000610ea282613abd565b60008080613a7c8585613ac7565b600081815260029690960160205260409095205494959350505050565b60006118ab8383613ad3565b60006118ab8383613aeb565b60006118ab8383613b3a565b6000610ea2825490565b60006118ab8383613c2d565b600081815260018301602052604081205415156118ab565b6000818152600183016020526040812054613b3257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610ea2565b506000610ea2565b60008181526001830160205260408120548015613c23576000613b5e600183615344565b8554909150600090613b7290600190615344565b9050818114613bd7576000866000018281548110613b9257613b92614afb565b9060005260206000200154905080876000018481548110613bb557613bb5614afb565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613be857613be8615357565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610ea2565b6000915050610ea2565b6000826000018281548110613c4457613c44614afb565b9060005260206000200154905092915050565b6001600160a01b0381168114612c0157600080fd5b8035610ea881613c57565b600080600080600060a08688031215613c8f57600080fd5b8535613c9a81613c57565b94506020860135613caa81613c57565b93506040860135613cba81613c57565b92506060860135613cca81613c57565b91506080860135613cda81613c57565b809150509295509295909350565b600060408284031215613cfa57600080fd5b50919050565b815181526020808301519082015260408101610ea2565b60008060408385031215613d2a57600080fd5b8235613d3581613c57565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613d8157613d81613d43565b604052919050565b60006001600160401b03821115613da257613da2613d43565b50601f01601f191660200190565b600082601f830112613dc157600080fd5b8135613dd4613dcf82613d89565b613d59565b818152846020838601011115613de957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613e1c57600080fd5b8435613e2781613c57565b93506020850135613e3781613c57565b92506040850135915060608501356001600160401b03811115613e5957600080fd5b613e6587828801613db0565b91505092959194509250565b600060208284031215613e8357600080fd5b81356001600160401b03811115613e9957600080fd5b6135dc84828501613db0565b600060208284031215613eb757600080fd5b5035919050565b60008083601f840112613ed057600080fd5b5081356001600160401b03811115613ee757600080fd5b6020830191508360208260061b850101111561340557600080fd5b60008060208385031215613f1557600080fd5b82356001600160401b03811115613f2b57600080fd5b613f3785828601613ebe565b90969095509350505050565b600060208284031215613f5557600080fd5b81356118ab81613c57565b60008083601f840112613f7257600080fd5b5081356001600160401b03811115613f8957600080fd5b60208301915083602082850101111561340557600080fd5b600080600080600060808688031215613fb957600080fd5b85359450602086013593506040860135925060608601356001600160401b03811115613fe457600080fd5b613ff088828901613f60565b969995985093965092949392505050565b8015158114612c0157600080fd5b6000806040838503121561402257600080fd5b823561402d81613c57565b9150602083013561403d81614001565b809150509250929050565b602080825282518282018190526000919060409081850190868401855b828110156140925761408284835180518252602090810151910152565b9284019290850190600101614065565b5091979650505050505050565b600080600080600080600060c0888a0312156140ba57600080fd5b8735965060208801359550604088013594506060880135935060808801356140e181613c57565b925060a08801356001600160401b038111156140fc57600080fd5b6141088a828b01613f60565b989b979a50959850939692959293505050565b6000806000806040858703121561413157600080fd5b84356001600160401b038082111561414857600080fd5b61415488838901613f60565b9096509450602087013591508082111561416d57600080fd5b5061417a87828801613f60565b95989497509550505050565b6000806000806000806000806000806101208b8d0312156141a657600080fd5b8a35995060208b0135985060408b0135975060608b0135965060808b0135955060a08b01356141d481613c57565b945060c08b01356141e481613c57565b935060e08b01356001600160401b038111156141ff57600080fd5b61420b8d828e01613f60565b915080945050809250506101008b013590509295989b9194979a5092959850565b60008083601f84011261423e57600080fd5b5081356001600160401b0381111561425557600080fd5b6020830191508360208260051b850101111561340557600080fd5b6000806020838503121561428357600080fd5b82356001600160401b0381111561429957600080fd5b613f378582860161422c565b600060808284031215613cfa57600080fd5b600081518084526020808501945080840160005b838110156142e7578151875295820195908201906001016142cb565b509495945050505050565b6020815260006118ab60208301846142b7565b60008060008060006060868803121561431d57600080fd5b85356001600160401b038082111561433457600080fd5b61434089838a01613f60565b9097509550602088013591508082111561435957600080fd5b5061436688828901613f60565b96999598509660400135949350505050565b60006001600160401b0382111561439157614391613d43565b5060051b60200190565b600082601f8301126143ac57600080fd5b813560206143bc613dcf83614378565b82815260059290921b840181019181810190868411156143db57600080fd5b8286015b848110156143f657803583529183019183016143df565b509695505050505050565b60008060008060008060008060006101208a8c03121561442057600080fd5b8935985060208a0135975060408a0135965060608a01356001600160401b038082111561444c57600080fd5b6144588d838e0161439b565b975060808c013591508082111561446e57600080fd5b61447a8d838e0161439b565b965061448860a08d01613c6c565b955061449660c08d01613c6c565b945060e08c01359150808211156144ac57600080fd5b506144b98c828d01613db0565b9250506101008a013590509295985092959850929598565b600080604083850312156144e457600080fd5b82356001600160401b03808211156144fb57600080fd5b818501915085601f83011261450f57600080fd5b8135602061451f613dcf83614378565b82815260059290921b8401810191818101908984111561453e57600080fd5b948201945b8386101561456557853561455681613c57565b82529482019490820190614543565b9650508601359250508082111561457b57600080fd5b506145888582860161439b565b9150509250929050565b600080600080600060a086880312156145aa57600080fd5b853594506020860135935060408601356001600160401b03808211156145cf57600080fd5b6145db89838a0161439b565b945060608801359150808211156145f157600080fd5b6145fd89838a0161439b565b9350608088013591508082111561461357600080fd5b5061462088828901613db0565b9150509295509295909350565b6000806000806000806000806000806101408b8d03121561464d57600080fd5b8a35995060208b0135985060408b0135975060608b01356001600160401b038082111561467957600080fd5b6146858e838f0161439b565b985060808d013591508082111561469b57600080fd5b6146a78e838f0161439b565b975060a08d01359150808211156146bd57600080fd5b6146c98e838f01613db0565b96506146d760c08e01613c6c565b95506146e560e08e01613c6c565b94506101008d01359150808211156146fc57600080fd5b506147098d828e01613db0565b9250506101208b013590509295989b9194979a5092959850565b60008060008060008060008060a0898b03121561473f57600080fd5b883561474a81613c57565b9750602089013561475a81613c57565b965060408901356001600160401b038082111561477657600080fd5b6147828c838d0161422c565b909850965060608b013591508082111561479b57600080fd5b6147a78c838d0161422c565b909650945060808b01359150808211156147c057600080fd5b506147cd8b828c01613f60565b999c989b5096995094979396929594505050565b600080604083850312156147f457600080fd5b50508035926020909101359150565b6000806020838503121561481657600080fd5b82356001600160401b038082111561482d57600080fd5b818501915085601f83011261484157600080fd5b81358181111561485057600080fd5b8660208260071b850101111561486557600080fd5b60209290920196919550909350505050565b60008060008060008060c0878903121561489057600080fd5b863595506020870135945060408701356001600160401b03808211156148b557600080fd5b6148c18a838b0161439b565b955060608901359150808211156148d757600080fd5b6148e38a838b0161439b565b9450608089013591506148f582613c57565b90925060a0880135908082111561490b57600080fd5b5061491889828a01613db0565b9150509295509295509295565b600080600080600060a0868803121561493d57600080fd5b853561494881613c57565b9450602086013561495881613c57565b9350604086013592506060860135915060808601356001600160401b0381111561498157600080fd5b61462088828901613db0565b60006020828403121561499f57600080fd5b81356118ab81614001565b6020808252600990820152682737ba1037bbb732b960b91b604082015260600190565b60005b838110156149e85781810151838201526020016149d0565b50506000910152565b60008251614a038184602087016149cd565b9190910192915050565b600060208284031215614a1f57600080fd5b5051919050565b600082601f830112614a3757600080fd5b8151614a45613dcf82613d89565b818152846020838601011115614a5a57600080fd5b6135dc8260208301602087016149cd565b60008060008060808587031215614a8157600080fd5b8451935060208501516001600160401b0380821115614a9f57600080fd5b614aab88838901614a26565b9450604087015193506060870151915080821115614ac857600080fd5b50613e6587828801614a26565b6020808252600c908201526b3737ba1037b832b930ba37b960a11b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201614b3957614b39614b11565b5060010190565b60208082526025908201527f43726f737344656c656761746556363a20416d6f756e742062656c6f77206d696040820152646e696d756d60d81b606082015260800190565b6020808252600990820152683737ba1030b236b4b760b91b604082015260600190565b60208082526018908201527f536d61727420636f6e74726163742069732068616c7465640000000000000000604082015260600190565b60006101408201905083825282516020830152602083015160408301526040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160018060a01b0380821660e085015260e08501519150610100818316818601528086015192505050614c676101208401826001600160a01b03169052565b509392505050565b828152604060208201528151604082015260208201516060820152604082015160808201526000606083015160e060a0840152614cb06101208401826142b7565b90506080840151603f198483030160c0850152614ccd82826142b7565b60a08601516001600160a01b0390811660e087015260c0909601519095166101009094019390935250919392505050565b87815286602082015285604082015260e060608201526000614d2360e08301876142b7565b8281036080840152614d3581876142b7565b6001600160a01b0395861660a08501529390941660c090920191909152509695505050505050565b60008151808452614d758160208601602086016149cd565b601f01601f19169290920160200192915050565b82815260406020820152815160408201526020820151606082015260408201516080820152600060608301516101008060a0850152614dcc6101408501836142b7565b91506080850151603f19808685030160c0870152614dea84836142b7565b935060a08701519150808685030160e087015250614e088382614d5d565b92505060c0850151614e24828601826001600160a01b03169052565b505060e08401516001600160a01b0381166101208501525b50949350505050565b60006101008a8352896020840152886040840152806060840152614e6b818401896142b7565b90508281036080840152614e7f81886142b7565b905082810360a0840152614e938187614d5d565b6001600160a01b0395861660c08501529390941660e09092019190915250979650505050505050565b60008060408385031215614ecf57600080fd5b8251614eda81613c57565b6020939093015192949293505050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b805160ff81168114610ea857600080fd5b600080600060608486031215614f4757600080fd5b614f5084614f21565b925060208401519150604084015190509250925092565b6020808252600f908201526e504b206973206e6f7420726561647960881b604082015260600190565b82815260406020820152815160408201526020820151606082015260006040830151610140806080850152614fc96101808501836142b7565b91506060850151603f19808685030160a0870152614fe784836142b7565b9350608087015160c087015260a087015160e087015260c08701519150610100828188015260e0880151925061012061502a818901856001600160a01b03169052565b8189015193508288870301858901526150438685614d5d565b955080890151945050505050614e3c6101608501826001600160a01b03169052565b82815260406020820152815160408201526020820151606082015260408201516080820152606082015160a0820152608082015160c082015260a082015160e0820152600060c08301516101008081850152506150c6610140840182614d5d565b60e094909401516001600160a01b03166101209390930192909252509092915050565b82815260406020820152815160408201526020820151606082015260408201516080820152606082015160a0820152608082015160c082015260a082015160e0820152600060c0830151610100818185015260e08501519150610120615159818601846001600160a01b03169052565b81860151925061014091508182860152615177610180860184614d5d565b908601516001600160a01b0381166101608701529092509050614e3c565b60008060008060008060008060008060006101608c8e0312156151b757600080fd5b8b519a506151c760208d01614f21565b995060408c0151985060608c0151975060808c0151965060a08c0151955060c08c0151945060e08c01516001600160401b0381111561520557600080fd5b6152118e828f01614a26565b9450506101008c01516001600160401b0381111561522e57600080fd5b61523a8e828f01614a26565b9350506101208c015191506101408c015190509295989b509295989b9093969950565b60006020828403121561526f57600080fd5b81516118ab81614001565b80820180821115610ea257610ea2614b11565b828152604060208201528151604082015260208201516060820152600060408301516101208060808501526152c66101608501836142b7565b91506060850151603f19808685030160a08701526152e484836142b7565b9350608087015160c087015260a087015160e087015260c08701519150610100828188015260e088015192508187860301848801526153238584614d5d565b9450808801519350505050614e3c6101408501826001600160a01b03169052565b81810381811115610ea257610ea2614b11565b634e487b7160e01b600052603160045260246000fdfea26469706673582212203694dd0e35297d9fe4b48651c4eb4b1dc0c416ecd2618e26f10a2f3ad64c170d64736f6c63430008120033
Loading...
Loading
Loading...
Loading
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.