Token
The Sandbox: ESTATE token (ESTATE)
ERC-721
Overview
Max Total Supply
0 ESTATE
Holders
1
Market
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract
Balance
2 ESTATELoading...
Loading
Loading...
Loading
Loading...
Loading
Contract Name:
ChildEstateTokenV1
Compiler Version
v0.8.2+commit.661d1103
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT 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. * * ``` * 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. */ 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; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. 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] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(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) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // 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); } // 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)))); } // 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 on 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)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/utils/Initializable.sol) pragma solidity ^0.8.0; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() initializer {} * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { // If the contract is initializing we ignore whether _initialized is set in order to support multiple // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the // contract may have been reentered. require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} modifier, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721ReceiverUpgradeable { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721Upgradeable is IERC165Upgradeable { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @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://diligence.consensys.net/posts/2019/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// 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 IERC165Upgradeable { /** * @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 pragma solidity 0.8.2; import "../common/BaseWithStorage/ImmutableERC721.sol"; import "../common/BaseWithStorage/WithMinter.sol"; import "../common/interfaces/IAssetToken.sol"; import "../common/interfaces/IGameToken.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract GameBaseToken is ImmutableERC721, WithMinter, Initializable, IGameToken { /////////////////////////////// Data ////////////////////////////// IAssetToken internal _asset; bytes4 private constant ERC1155_RECEIVED = 0xf23a6e61; bytes4 private constant ERC1155_BATCH_RECEIVED = 0xbc197c81; mapping(uint256 => mapping(uint256 => uint256)) private _gameAssets; mapping(uint256 => address) private _creatorship; // creatorship transfer mapping(uint256 => bytes32) private _metaData; mapping(address => mapping(address => bool)) private _gameEditors; mapping(uint256 => uint256) internal _exactNumOfLandsRequired; /////////////////////////////// Events ////////////////////////////// /// @dev Emits when a game is updated. /// @param oldId The id of the previous erc721 GAME token. /// @param newId The id of the newly minted token. /// @param update The changes made to the Game: new assets, removed assets, uri event GameTokenUpdated(uint256 indexed oldId, uint256 indexed newId, IGameToken.GameData update); /// @dev Emits when creatorship of a GAME token is transferred. /// @param original The original creator of the GAME token. /// @param from The current 'creator' of the token. /// @param to The new 'creator' of the token. event CreatorshipTransfer(address indexed original, address indexed from, address indexed to); /// @dev Emits when an address has its gameEditor status changed. /// @param gameOwner The owner of the GAME token. /// @param gameEditor The address whose editor rights to update. /// @param isEditor WHether the address 'gameEditor' should be an editor. event GameEditorSet(address indexed gameOwner, address gameEditor, bool isEditor); function initV1( address trustedForwarder, address admin, IAssetToken asset, uint8 chainIndex ) public initializer() { _admin = admin; _asset = asset; ERC721BaseToken.__ERC721BaseToken_initialize(chainIndex); ERC2771Handler.__ERC2771Handler_initialize(trustedForwarder); } /////////////////////////////// Modifiers ////////////////////////////// modifier notToZero(address to) { require(to != address(0), "DESTINATION_ZERO_ADDRESS"); _; } modifier notToThis(address to) { require(to != address(this), "DESTINATION_GAME_CONTRACT"); _; } /////////////////////////////// Functions ////////////////////////////// /// @notice Create a new GAME token. /// @param from The address of the one creating the game (may be different from msg.sender if metaTx). /// @param to The address who will be assigned ownership of this game. /// @param creation The struct containing ids & ammounts of assets to add to this game, /// along with the uri to set. /// @param editor The address to allow to edit (can also be set later). /// @param subId A random id created on the backend. /// @return id The id of the new GAME token (erc721). function createGame( address from, address to, GameData calldata creation, address editor, uint64 subId ) external override onlyMinter() notToZero(to) notToThis(to) returns (uint256 id) { require(creation.exactNumOfLandsRequired > 0, "EXACT_NUM_OF_LANDS_REQUIRED_ZERO"); (uint256 gameId, uint256 strgId) = _mintGame(from, to, subId, 0, true); if (editor != address(0)) { _setGameEditor(to, editor, true); } if (creation.assetIdsToAdd.length != 0) { _addAssets(from, strgId, creation.assetIdsToAdd, creation.assetAmountsToAdd); } _metaData[strgId] = creation.uri; _exactNumOfLandsRequired[strgId] = creation.exactNumOfLandsRequired; emit GameTokenUpdated(0, gameId, creation); return gameId; } /// @notice Update an existing GAME token.This actually burns old token /// and mints new token with same basId & incremented version. /// @param from The one updating the GAME token. /// @param gameId The current id of the GAME token. /// @param update The values to use for the update. /// @return The new gameId. function updateGame( address from, uint256 gameId, IGameToken.GameData memory update ) external override onlyMinter() returns (uint256) { require(update.exactNumOfLandsRequired > 0, "EXACT_NUM_OF_LANDS_REQUIRED_ZERO"); uint256 id = _storageId(gameId); _addAssets(from, id, update.assetIdsToAdd, update.assetAmountsToAdd); _removeAssets(id, update.assetIdsToRemove, update.assetAmountsToRemove, _ownerOf(gameId)); _metaData[id] = update.uri; _exactNumOfLandsRequired[id] = update.exactNumOfLandsRequired; uint256 newId = _bumpGameVersion(from, gameId); emit GameTokenUpdated(gameId, newId, update); return newId; } /// @notice Allow token owner to set game editors. /// @param gameOwner The address of a GAME token creator. /// @param editor The address of the editor to set. /// @param isEditor Add or remove the ability to edit. function setGameEditor( address gameOwner, address editor, bool isEditor ) external override { require(_msgSender() == gameOwner, "EDITOR_ACCESS_DENIED"); _setGameEditor(gameOwner, editor, isEditor); } /// @notice Transfers creatorship of `original` from `sender` to `to`. /// @param gameId The current id of the GAME token. /// @param sender The address of current registered creator. /// @param to The address to transfer the creatorship to function transferCreatorship( uint256 gameId, address sender, address to ) external override notToZero(to) { require(_ownerOf(gameId) != address(0), "NONEXISTENT_TOKEN"); uint256 id = _storageId(gameId); address msgSender = _msgSender(); require(msgSender == sender || _superOperators[msgSender], "TRANSFER_ACCESS_DENIED"); require(sender != address(0), "NOT_FROM_ZEROADDRESS"); address originalCreator = address(uint160(id / CREATOR_OFFSET_MULTIPLIER)); address current = creatorOf(gameId); require(current != to, "CURRENT_=_TO"); require(current == sender, "CURRENT_!=_SENDER"); _creatorship[id] = to; emit CreatorshipTransfer(originalCreator, current, to); } /// @notice Burn a GAME token and recover assets. /// @param from The address of the one destroying the game. /// @param to The address to send all GAME assets to. /// @param gameId The id of the GAME to destroy. /// @param assetIds The assets to recover from the burnt GAME. function burnAndRecover( address from, address to, uint256 gameId, uint256[] calldata assetIds ) external override { _burnGame(from, gameId); _recoverAssets(from, to, gameId, assetIds); } /// @notice Burn a GAME token. /// @param gameId The id of the GAME to destroy. function burn(uint256 gameId) external override(ERC721BaseToken, IGameToken) { _burnGame(_msgSender(), gameId); } /// @notice Burn a GAME token on behalf of owner. /// @param from The address whose GAME is being burnt. /// @param gameId The id of the GAME to burn. function burnFrom(address from, uint256 gameId) external override(ERC721BaseToken, IGameToken) { require(from != address(0), "NOT_FROM_ZEROADDRESS"); _burnGame(from, gameId); } /// @notice Transfer assets from a burnt GAME. /// @param from Previous owner of the burnt game. /// @param to Address that will receive the assets. /// @param gameId Id of the burnt GAME token. /// @param assetIds The assets to recover from the burnt GAME. function recoverAssets( address from, address to, uint256 gameId, uint256[] memory assetIds ) public override { _recoverAssets(from, to, gameId, assetIds); } /// @notice Get the amount of each assetId in a GAME. /// @param gameId The game to query. /// @param assetIds The assets to get balances for. function getAssetBalances(uint256 gameId, uint256[] calldata assetIds) external view override returns (uint256[] memory) { uint256 storageId = _storageId(gameId); require(_ownerOf(gameId) != address(0), "NONEXISTENT_TOKEN"); uint256 length = assetIds.length; uint256[] memory assets; assets = new uint256[](length); for (uint256 i = 0; i < length; i++) { assets[i] = _gameAssets[storageId][assetIds[i]]; } return assets; } function getExactNumOfLandsRequired(uint256 gameId) external view override returns (uint256) { uint256 storageId = _storageId(gameId); return _exactNumOfLandsRequired[storageId]; } /// @notice Get game editor status. /// @param gameOwner The address of the owner of the GAME. /// @param editor The address of the editor to set. /// @return isEditor Editor status of editor for given tokenId. function isGameEditor(address gameOwner, address editor) external view override returns (bool isEditor) { return _gameEditors[gameOwner][editor]; } /// @notice Called by other contracts to check if this can receive erc1155 batch. /// @param operator The address of the operator in the current tx. /// @return the bytes4 value 0xbc197c81. function onERC1155BatchReceived( address operator, address, /*from*/ uint256[] calldata, /*ids*/ uint256[] calldata, /*values*/ bytes calldata /*data*/ ) external view override returns (bytes4) { if (operator == address(this)) { return ERC1155_BATCH_RECEIVED; } revert("ERC1155_BATCH_REJECTED"); } /// @notice Called by other contracts to check if this can receive erc1155 tokens. /// @param operator The address of the operator in the current tx. /// @return the bytes4 value 0xf23a6e61. function onERC1155Received( address operator, address, /*from*/ uint256, /*id*/ uint256, /*value*/ bytes calldata /*data*/ ) external view override returns (bytes4) { if (operator == address(this)) { return ERC1155_RECEIVED; } revert("ERC1155_REJECTED"); } /// @notice Return the name of the token contract. /// @return The name of the token contract. function name() external pure override returns (string memory) { return "The Sandbox: GAME token"; } /// @notice Get the symbol of the token contract. /// @return the symbol of the token contract. function symbol() external pure override returns (string memory) { return "GAME"; } /// @notice Get the creator of the token type `id`. /// @param gameId The id of the token to get the creator of. /// @return the creator of the token type `id`. function creatorOf(uint256 gameId) public view override returns (address) { require(gameId != uint256(0), "GAME_NEVER_MINTED"); uint256 id = _storageId(gameId); address originalCreator = address(uint160(id / CREATOR_OFFSET_MULTIPLIER)); address newCreator = _creatorship[id]; if (newCreator != address(0)) { return newCreator; } return originalCreator; } /// @notice Return the URI of a specific token. /// @param gameId The id of the token. /// @return uri The URI of the token metadata. function tokenURI(uint256 gameId) public view override returns (string memory uri) { require(_ownerOf(gameId) != address(0), "BURNED_OR_NEVER_MINTED"); uint256 id = _storageId(gameId); return _toFullURI(_metaData[id]); } /// @notice Check if the contract supports an interface. /// 0x01ffc9a7 is ERC-165. /// 0x80ac58cd is ERC-721. /// @param id The id of the interface. /// @return if the interface is supported. function supportsInterface(bytes4 id) public pure override returns (bool) { return id == 0x01ffc9a7 || id == 0x80ac58cd || id == 0x5b5e139f; } /// @notice Add assets to an existing GAME. /// @param from The address of the current owner of assets. /// @param strgId The storageId of the GAME to add assets to. /// @param assetIds The id of the asset to add to GAME. /// @param amounts The amount of each asset to add to GAME. function _addAssets( address from, uint256 strgId, uint256[] memory assetIds, uint256[] memory amounts ) internal { if (assetIds.length == 0) { return; } require(assetIds.length == amounts.length, "INVALID_INPUT_LENGTHS"); uint256 currentValue; for (uint256 i = 0; i < assetIds.length; i++) { currentValue = _gameAssets[strgId][assetIds[i]]; require(amounts[i] != 0, "INVALID_ASSET_ADDITION"); _gameAssets[strgId][assetIds[i]] = currentValue + amounts[i]; } if (assetIds.length == 1) { _asset.safeTransferFrom(from, address(this), assetIds[0], amounts[0], ""); } else { _asset.safeBatchTransferFrom(from, address(this), assetIds, amounts, ""); } } /// @notice Remove assets from a GAME. /// @param id The storageId of the GAME to remove assets from. /// @param assetIds An array of asset Ids to remove. /// @param values An array of the number of each asset id to remove. /// @param to The address to send removed assets to. function _removeAssets( uint256 id, uint256[] memory assetIds, uint256[] memory values, address to ) internal { if (assetIds.length == 0) { return; } require(assetIds.length == values.length && assetIds.length != 0, "INVALID_INPUT_LENGTHS"); uint256 currentValue; for (uint256 i = 0; i < assetIds.length; i++) { currentValue = _gameAssets[id][assetIds[i]]; require(currentValue != 0 && values[i] != 0 && values[i] <= currentValue, "INVALID_ASSET_REMOVAL"); _gameAssets[id][assetIds[i]] = currentValue - values[i]; } if (assetIds.length == 1) { _asset.safeTransferFrom(address(this), to, assetIds[0], values[0], ""); } else { _asset.safeBatchTransferFrom(address(this), to, assetIds, values, ""); } } /// @dev See burn / burnFrom. function _burnGame(address from, uint256 gameId) internal { uint256 storageId = _storageId(gameId); (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(storageId); address msgSender = _msgSender(); require( msgSender == owner || (operatorEnabled && _operators[storageId] == msgSender) || _superOperators[msgSender] || _operatorsForAll[from][msgSender], "UNAUTHORIZED_BURN" ); delete _metaData[storageId]; delete _exactNumOfLandsRequired[storageId]; _creatorship[gameId] = address(0); _burn(from, owner, gameId); } /// @dev See recoverAssets. function _recoverAssets( address from, address to, uint256 gameId, uint256[] memory assetIds ) internal notToZero(to) notToThis(to) { require(_ownerOf(gameId) == address(0), "ONLY_FROM_BURNED_TOKEN"); uint256 storageId = _storageId(gameId); require(from == _msgSender(), "INVALID_RECOVERY"); _check_withdrawal_authorized(from, gameId); require(assetIds.length > 0, "WITHDRAWAL_COMPLETE"); uint256[] memory values; values = new uint256[](assetIds.length); for (uint256 i = 0; i < assetIds.length; i++) { values[i] = _gameAssets[storageId][assetIds[i]]; delete _gameAssets[storageId][assetIds[i]]; } _asset.safeBatchTransferFrom(address(this), to, assetIds, values, ""); GameData memory recovery; recovery.assetIdsToRemove = assetIds; recovery.assetAmountsToRemove = values; emit GameTokenUpdated(gameId, 0, recovery); } /// @dev Create a new gameId and associate it with an owner. /// @param from The address of one creating the game. /// @param to The address of the Game owner. /// @param subId The id to use when generating the new GameId. /// @param version The version number part of the gameId. /// @param isCreation Whether this is a brand new GAME (as opposed to an update). /// @return id The newly created gameId. function _mintGame( address from, address to, uint64 subId, uint16 version, bool isCreation ) internal returns (uint256 id, uint256 storageId) { uint16 idVersion; uint256 gameId; uint256 strgId; if (isCreation) { idVersion = 1; gameId = _generateTokenId(from, subId, _chainIndex, idVersion); strgId = _storageId(gameId); require(_owners[strgId] == 0, "STORAGE_ID_REUSE_FORBIDDEN"); } else { idVersion = version; gameId = _generateTokenId(from, subId, _chainIndex, idVersion); strgId = _storageId(gameId); } _owners[strgId] = (uint256(idVersion) << 200) + uint256(uint160(to)); _numNFTPerAddress[to]++; emit Transfer(address(0), to, gameId); return (gameId, strgId); } /// @dev Allow token owner to set game editors. /// @param gameCreator The address of a GAME creator, /// @param editor The address of the editor to set. /// @param isEditor Add or remove the ability to edit. function _setGameEditor( address gameCreator, address editor, bool isEditor ) internal { emit GameEditorSet(gameCreator, editor, isEditor); _gameEditors[gameCreator][editor] = isEditor; } /// @dev Bumps the version number of a game token, buring the previous /// version and minting a new one. /// @param from The address of the GAME token owner. /// @param gameId The Game token to bump the version of. /// @return The new gameId. function _bumpGameVersion(address from, uint256 gameId) internal returns (uint256) { address originalCreator = address(uint160(gameId / CREATOR_OFFSET_MULTIPLIER)); uint64 subId = uint64(gameId / SUBID_MULTIPLIER); uint16 version = uint16(gameId); version++; address owner = _ownerOf(gameId); if (from == owner) { // caller is owner or metaTx on owner's behalf _burn(from, owner, gameId); } else if (_gameEditors[owner][from]) { // caller is editor or metaTx on editor's behalf, so we need to pass owner // instead of from or _burn will fail _burn(owner, owner, gameId); } (uint256 newId, ) = _mintGame(originalCreator, owner, subId, version, false); address newOwner = _ownerOf(newId); assert(owner == newOwner); return newId; } /// @dev Get the a full URI string for a given hash + gameId. /// @param hash The 32 byte IPFS hash. /// @return The URI string. function _toFullURI(bytes32 hash) internal pure override returns (string memory) { return string(abi.encodePacked("ipfs://bafybei", hash2base32(hash), "/", "game.json")); } }
// SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity ^0.8.0; /// @dev minimal ERC2771 handler to keep bytecode-size down. /// based on: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/metatx/ERC2771Context.sol contract ERC2771Handler { address internal _trustedForwarder; function __ERC2771Handler_initialize(address forwarder) internal { _trustedForwarder = forwarder; } function isTrustedForwarder(address forwarder) public view returns (bool) { return forwarder == _trustedForwarder; } function getTrustedForwarder() external view returns (address trustedForwarder) { return _trustedForwarder; } function _msgSender() internal view virtual returns (address sender) { if (isTrustedForwarder(msg.sender)) { // The assembly code is more direct than the Solidity version using `abi.decode`. // solhint-disable-next-line no-inline-assembly assembly { sender := shr(96, calldataload(sub(calldatasize(), 20))) } } else { return msg.sender; } } function _msgData() internal view virtual returns (bytes calldata) { if (isTrustedForwarder(msg.sender)) { return msg.data[:msg.data.length - 20]; } else { return msg.data; } } }
//SPDX-License-Identifier: MIT /* solhint-disable func-order, code-complexity */ pragma solidity 0.8.2; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; import "./WithSuperOperators.sol"; import "../interfaces/IERC721MandatoryTokenReceiver.sol"; import "./ERC2771Handler.sol"; contract ERC721BaseToken is IERC721Upgradeable, WithSuperOperators, ERC2771Handler { using AddressUpgradeable for address; bytes4 internal constant _ERC721_RECEIVED = 0x150b7a02; bytes4 internal constant _ERC721_BATCH_RECEIVED = 0x4b808c46; bytes4 internal constant ERC165ID = 0x01ffc9a7; bytes4 internal constant ERC721_MANDATORY_RECEIVER = 0x5e8bf644; uint256 internal constant NOT_ADDRESS = 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000; uint256 internal constant OPERATOR_FLAG = (2**255); uint256 internal constant NOT_OPERATOR_FLAG = OPERATOR_FLAG - 1; uint256 internal constant BURNED_FLAG = (2**160); mapping(address => uint256) internal _numNFTPerAddress; mapping(uint256 => uint256) internal _owners; mapping(address => mapping(address => bool)) internal _operatorsForAll; mapping(uint256 => address) internal _operators; uint8 internal _chainIndex; function __ERC721BaseToken_initialize(uint8 chainIndex) internal { _chainIndex = chainIndex; } /// @notice Approve an operator to spend tokens on the senders behalf. /// @param operator The address receiving the approval. /// @param id The id of the token. function approve(address operator, uint256 id) external override { uint256 ownerData = _owners[_storageId(id)]; address owner = _ownerOf(id); address msgSender = _msgSender(); require(owner != address(0), "NONEXISTENT_TOKEN"); require( owner == msgSender || _superOperators[msgSender] || _operatorsForAll[owner][msgSender], "UNAUTHORIZED_APPROVAL" ); _approveFor(ownerData, operator, id); } /// @notice Approve an operator to spend tokens on the sender behalf. /// @param sender The address giving the approval. /// @param operator The address receiving the approval. /// @param id The id of the token. function approveFor( address sender, address operator, uint256 id ) external { uint256 ownerData = _owners[_storageId(id)]; address msgSender = _msgSender(); require(sender != address(0), "ZERO_ADDRESS_SENDER"); require( msgSender == sender || _superOperators[msgSender] || _operatorsForAll[sender][msgSender], "UNAUTHORIZED_APPROVAL" ); require(address(uint160(ownerData)) == sender, "OWNER_NOT_SENDER"); _approveFor(ownerData, operator, id); } /// @notice Transfer a token between 2 addresses. /// @param from The sender of the token. /// @param to The recipient of the token. /// @param id The id of the token. function transferFrom( address from, address to, uint256 id ) external override { _checkTransfer(from, to, id); _transferFrom(from, to, id); if (to.isContract() && _checkInterfaceWith10000Gas(to, ERC721_MANDATORY_RECEIVER)) { require(_checkOnERC721Received(_msgSender(), from, to, id, ""), "ERC721_TRANSFER_REJECTED"); } } /// @notice Transfer a token between 2 addresses letting the receiver know of the transfer. /// @param from The send of the token. /// @param to The recipient of the token. /// @param id The id of the token. function safeTransferFrom( address from, address to, uint256 id ) external override { safeTransferFrom(from, to, id, ""); } /// @notice Transfer many tokens between 2 addresses. /// @param from The sender of the token. /// @param to The recipient of the token. /// @param ids The ids of the tokens. /// @param data Additional data. function batchTransferFrom( address from, address to, uint256[] calldata ids, bytes calldata data ) external { _batchTransferFrom(from, to, ids, data, false); } /// @notice Transfer many tokens between 2 addresses, while /// ensuring the receiving contract has a receiver method. /// @param from The sender of the token. /// @param to The recipient of the token. /// @param ids The ids of the tokens. /// @param data Additional data. function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, bytes calldata data ) external { _batchTransferFrom(from, to, ids, data, true); } /// @notice Set the approval for an operator to manage all the tokens of the sender. /// @param sender The address giving the approval. /// @param operator The address receiving the approval. /// @param approved The determination of the approval. function setApprovalForAllFor( address sender, address operator, bool approved ) external { require(sender != address(0), "Invalid sender address"); address msgSender = _msgSender(); require(msgSender == sender || _superOperators[msgSender], "UNAUTHORIZED_APPROVE_FOR_ALL"); _setApprovalForAll(sender, operator, approved); } /// @notice Set the approval for an operator to manage all the tokens of the sender. /// @param operator The address receiving the approval. /// @param approved The determination of the approval. function setApprovalForAll(address operator, bool approved) external override { _setApprovalForAll(_msgSender(), operator, approved); } /// @notice Burns token `id`. /// @param id The token which will be burnt. function burn(uint256 id) external virtual { _burn(_msgSender(), _ownerOf(id), id); } /// @notice Burn token`id` from `from`. /// @param from address whose token is to be burnt. /// @param id The token which will be burnt. function burnFrom(address from, uint256 id) external virtual { require(from != address(0), "NOT_FROM_ZEROADDRESS"); (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id); address msgSender = _msgSender(); require( msgSender == from || (operatorEnabled && _operators[id] == msgSender) || _superOperators[msgSender] || _operatorsForAll[from][msgSender], "UNAUTHORIZED_BURN" ); _burn(from, owner, id); } /// @notice Get the number of tokens owned by an address. /// @param owner The address to look for. /// @return The number of tokens owned by the address. function balanceOf(address owner) external view override returns (uint256) { require(owner != address(0), "ZERO_ADDRESS_OWNER"); return _numNFTPerAddress[owner]; } /// @notice Get the owner of a token. /// @param id The id of the token. /// @return owner The address of the token owner. function ownerOf(uint256 id) external view override returns (address owner) { owner = _ownerOf(id); require(owner != address(0), "NONEXISTANT_TOKEN"); } /// @notice Get the approved operator for a specific token. /// @param id The id of the token. /// @return The address of the operator. function getApproved(uint256 id) external view override returns (address) { (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id); require(owner != address(0), "NONEXISTENT_TOKEN"); if (operatorEnabled) { return _operators[id]; } else { return address(0); } } /// @notice Check if the sender approved the operator. /// @param owner The address of the owner. /// @param operator The address of the operator. /// @return isOperator The status of the approval. function isApprovedForAll(address owner, address operator) external view override returns (bool isOperator) { return _operatorsForAll[owner][operator] || _superOperators[operator]; } /// @notice Transfer a token between 2 addresses letting the receiver knows of the transfer. /// @param from The sender of the token. /// @param to The recipient of the token. /// @param id The id of the token. /// @param data Additional data. function safeTransferFrom( address from, address to, uint256 id, bytes memory data ) public override { _checkTransfer(from, to, id); _transferFrom(from, to, id); if (to.isContract()) { require(_checkOnERC721Received(_msgSender(), from, to, id, data), "ERC721_TRANSFER_REJECTED"); } } /// @notice Check if the contract supports an interface. /// 0x01ffc9a7 is ERC-165. /// 0x80ac58cd is ERC-721 /// @param id The id of the interface. /// @return Whether the interface is supported. function supportsInterface(bytes4 id) public pure virtual override returns (bool) { return id == 0x01ffc9a7 || id == 0x80ac58cd; } function isBurned(uint256 estateId) public view returns (bool) { uint256 storageId = _storageId(estateId); return (_owners[storageId] & BURNED_FLAG) == BURNED_FLAG; } /// @dev By overriding this function in an implementation which inherits this contract, you can enable versioned tokenIds without the extra overhead of writing to a new storage slot in _owners each time a version is incremented. See GameToken._storageId() for an example, where the storageId is the tokenId minus the version number. /// !!! Caution !!! Overriding this function without taking appropriate care could lead to /// ownerOf() returning an owner for non-existent tokens. Tests should be written to /// guard against introducing this bug. /// @param id The id of a token. /// @return The id used for storage mappings. function _storageId(uint256 id) internal view virtual returns (uint256) { return id; } function _updateOwnerData( uint256 id, uint256 oldData, address newOwner, bool hasOperator ) internal virtual { if (hasOperator) { _owners[_storageId(id)] = (oldData & NOT_ADDRESS) | OPERATOR_FLAG | uint256(uint160(newOwner)); } else { _owners[_storageId(id)] = ((oldData & NOT_ADDRESS) & NOT_OPERATOR_FLAG) | uint256(uint160(newOwner)); } } function _transferFrom( address from, address to, uint256 id ) internal { _numNFTPerAddress[from]--; _numNFTPerAddress[to]++; _updateOwnerData(id, _owners[_storageId(id)], to, false); emit Transfer(from, to, id); } /// @dev See approveFor. function _approveFor( uint256 ownerData, address operator, uint256 id ) internal { address owner = _ownerOf(id); if (operator == address(0)) { _updateOwnerData(id, ownerData, owner, false); } else { _updateOwnerData(id, ownerData, owner, true); _operators[id] = operator; } emit Approval(owner, operator, id); } /// @dev See batchTransferFrom. function _batchTransferFrom( address from, address to, uint256[] memory ids, bytes memory data, bool safe ) internal { address msgSender = _msgSender(); bool authorized = msgSender == from || _superOperators[msgSender] || _operatorsForAll[from][msgSender]; require(from != address(0), "NOT_FROM_ZEROADDRESS"); require(to != address(0), "NOT_TO_ZEROADDRESS"); uint256 numTokens = ids.length; for (uint256 i = 0; i < ids.length; i++) { uint256 id = ids[i]; if (id == 0) { numTokens--; continue; } (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id); require(owner == from, "BATCHTRANSFERFROM_NOT_OWNER"); require(authorized || (operatorEnabled && _operators[id] == msgSender), "NOT_AUTHORIZED"); _updateOwnerData(id, _owners[_storageId(id)], to, false); emit Transfer(from, to, id); } if (from != to) { _numNFTPerAddress[from] -= numTokens; _numNFTPerAddress[to] += numTokens; } if (to.isContract() && (safe || _checkInterfaceWith10000Gas(to, ERC721_MANDATORY_RECEIVER))) { require(_checkOnERC721BatchReceived(msgSender, from, to, ids, data), "ERC721_BATCH_TRANSFER_REJECTED"); } } /// @dev See setApprovalForAll. function _setApprovalForAll( address sender, address operator, bool approved ) internal { require(!_superOperators[operator], "INVALID_APPROVAL_CHANGE"); _operatorsForAll[sender][operator] = approved; emit ApprovalForAll(sender, operator, approved); } /// @dev See burn. function _burn( address from, address owner, uint256 id ) internal { require(from == owner, "NOT_OWNER"); uint256 storageId = _storageId(id); _owners[storageId] = (_owners[storageId] & NOT_OPERATOR_FLAG) | BURNED_FLAG; // record as non owner but keep track of last owner _numNFTPerAddress[from]--; emit Transfer(from, address(0), id); } /// @dev Check if receiving contract accepts erc721 transfers. /// @param operator The address of the operator. /// @param from The from address, may be different from msg.sender. /// @param to The adddress we want to transfer to. /// @param tokenId The id of the token we would like to transfer. /// @param _data Any additional data to send with the transfer. /// @return Whether the expected value of 0x150b7a02 is returned. function _checkOnERC721Received( address operator, address from, address to, uint256 tokenId, bytes memory _data ) internal returns (bool) { bytes4 retval = IERC721ReceiverUpgradeable(to).onERC721Received(operator, from, tokenId, _data); return (retval == _ERC721_RECEIVED); } /// @dev Check if receiving contract accepts erc721 batch transfers. /// @param operator The address of the operator. /// @param from The from address, may be different from msg.sender. /// @param to The adddress we want to transfer to. /// @param ids The ids of the tokens we would like to transfer. /// @param _data Any additional data to send with the transfer. /// @return Whether the expected value of 0x4b808c46 is returned. function _checkOnERC721BatchReceived( address operator, address from, address to, uint256[] memory ids, bytes memory _data ) internal returns (bool) { bytes4 retval = IERC721MandatoryTokenReceiver(to).onERC721BatchReceived(operator, from, ids, _data); return (retval == _ERC721_BATCH_RECEIVED); } /// @dev See ownerOf function _ownerOf(uint256 id) internal view virtual returns (address) { uint256 data = _owners[_storageId(id)]; if ((data & BURNED_FLAG) == BURNED_FLAG) { return address(0); } return address(uint160(data)); } /// @dev Get the owner and operatorEnabled status of a token. /// @param id The token to query. /// @return owner The owner of the token. /// @return operatorEnabled Whether or not operators are enabled for this token. function _ownerAndOperatorEnabledOf(uint256 id) internal view virtual returns (address owner, bool operatorEnabled) { uint256 data = _owners[_storageId(id)]; if ((data & BURNED_FLAG) == BURNED_FLAG) { owner = address(0); } else { owner = address(uint160(data)); } operatorEnabled = (data & OPERATOR_FLAG) == OPERATOR_FLAG; } /// @dev Check whether a transfer is a meta Transaction or not. /// @param from The address who initiated the transfer (may differ from msg.sender). /// @param to The address recieving the token. /// @param id The token being transferred. /// @return isMetaTx Whether or not the transaction is a MetaTx. function _checkTransfer( address from, address to, uint256 id ) internal view returns (bool isMetaTx) { (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id); address msgSender = _msgSender(); require(owner != address(0), "NONEXISTENT_TOKEN"); require(owner == from, "CHECKTRANSFER_NOT_OWNER"); require(to != address(0), "NOT_TO_ZEROADDRESS"); require( msgSender == owner || _superOperators[msgSender] || _operatorsForAll[from][msgSender] || (operatorEnabled && _operators[id] == msgSender), "UNAUTHORIZED_TRANSFER" ); return true; } /// @dev Check if there was enough gas. /// @param _contract The address of the contract to check. /// @param interfaceId The id of the interface we want to test. /// @return Whether or not this check succeeded. function _checkInterfaceWith10000Gas(address _contract, bytes4 interfaceId) internal view returns (bool) { bool success; bool result; bytes memory callData = abi.encodeWithSelector(ERC165ID, interfaceId); // solhint-disable-next-line no-inline-assembly assembly { let call_ptr := add(0x20, callData) let call_size := mload(callData) let output := mload(0x40) // Find empty storage location using "free memory pointer" mstore(output, 0x0) success := staticcall(10000, _contract, call_ptr, call_size, output, 0x20) // 32 bytes result := mload(output) } // (10000 / 63) "not enough for supportsInterface(...)" // consume all gas, so caller can potentially know that there was not enough gas assert(gasleft() > 158); return success && result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../BaseWithStorage/ERC721BaseToken.sol"; contract ImmutableERC721 is ERC721BaseToken { uint256 internal constant CREATOR_OFFSET_MULTIPLIER = uint256(2)**(256 - 160); uint256 internal constant SUBID_MULTIPLIER = uint256(2)**(256 - 224); uint256 internal constant CHAIN_INDEX_OFFSET_MULTIPLIER = uint256(2)**(256 - 160 - 64 - 16); uint256 internal constant STORAGE_ID_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000; uint256 internal constant VERSION_MASK = 0x000000FFFFFFFF00000000000000000000000000000000000000000000000000; bytes32 internal constant base32Alphabet = 0x6162636465666768696A6B6C6D6E6F707172737475767778797A323334353637; /// @dev An implementation which handles versioned tokenIds. /// @param id The tokenId to get the owner of. /// @return The address of the owner. function _ownerOf(uint256 id) internal view virtual override returns (address) { uint256 packedData = _owners[_storageId(id)]; uint16 idVersion = uint16(id); uint16 storageVersion = uint16((packedData & VERSION_MASK) >> 200); if (((packedData & BURNED_FLAG) == BURNED_FLAG) || idVersion != storageVersion) { return address(0); //should be here } return address(uint160(packedData)); } /// @dev Check if a withdrawal is allowed. /// @param from The address requesting the withdrawal. /// @param tokenId The id of the token to withdraw assets from. function _check_withdrawal_authorized(address from, uint256 tokenId) internal view virtual { require(from != address(uint160(0)), "SENDER_ZERO_ADDRESS"); require(from == _withdrawalOwnerOf(tokenId), "LAST_OWNER_NOT_EQUAL_SENDER"); } /// @dev Get the address allowed to withdraw associated tokens from the parent token. /// If too many associated tokens in TOKEN, block.gaslimit won't allow detroy and withdraw in 1 tx. /// An owner may destroy their token, then withdraw associated tokens in a later tx (even /// though ownerOf(id) would be address(0) after burning.) /// @param id The id of the token to query. /// @return the address of the owner before burning. function _withdrawalOwnerOf(uint256 id) internal view virtual returns (address) { uint256 packedData = _owners[_storageId(id)]; return address(uint160(packedData)); } /// @notice Get the storageID (no chainIndex or version data), which is constant for a given token. /// @param tokenId The tokenId for which to find the first token Id. /// @return The storage id for this token. function getStorageId(uint256 tokenId) external pure virtual returns (uint256) { return _storageId(tokenId); } /// @dev Get the storageId (full id without the version number) from the full tokenId. /// @param id The full tokenId for the GAME token. /// @return The storageId. function _storageId(uint256 id) internal pure virtual override returns (uint256) { return uint256(id & STORAGE_ID_MASK); } /// @dev Get the a full URI string for a given hash + gameId. /// @param hash The 32 byte IPFS hash. /// @return The URI string. function _toFullURI(bytes32 hash) internal pure virtual returns (string memory) { return string(abi.encodePacked("ipfs://bafybei", hash2base32(hash), "/", "token.json")); } /// @dev Create a new tokenId and associate it with an owner. /// This is a packed id, consisting of 4 parts: /// the creator's address, a uint64 subId, a uint18 chainIndex and a uint16 version. /// @param creator The address of the Token creator. /// @param subId The id used to generate the id. /// @param version The publicversion used to generate the id. function _generateTokenId( address creator, uint64 subId, uint8 chainIndex, uint16 version ) internal pure returns (uint256) { return uint256(uint160(creator)) * CREATOR_OFFSET_MULTIPLIER + uint64(subId) * SUBID_MULTIPLIER + chainIndex * CHAIN_INDEX_OFFSET_MULTIPLIER + uint16(version); } /// @dev Convert a 32 byte hash to a base 32 string. /// @param hash A 32 byte (IPFS) hash. /// @return _uintAsString The hash as a base 32 string. // solhint-disable-next-line security/no-assign-params function hash2base32(bytes32 hash) internal pure returns (string memory _uintAsString) { uint256 _i = uint256(hash); uint256 k = 52; bytes memory bstr = new bytes(k); bstr[--k] = base32Alphabet[uint8((_i % 8) << 2)]; // uint8 s = uint8((256 - skip) % 5); // (_i % (2**s)) << (5-s) _i /= 8; while (k > 0) { bstr[--k] = base32Alphabet[_i % 32]; _i /= 32; } return string(bstr); } }
//SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity 0.8.2; contract WithAdmin { address internal _admin; /// @dev Emits when the contract administrator is changed. /// @param oldAdmin The address of the previous administrator. /// @param newAdmin The address of the new administrator. event AdminChanged(address oldAdmin, address newAdmin); modifier onlyAdmin() { require(msg.sender == _admin, "ADMIN_ONLY"); _; } /// @dev Get the current administrator of this contract. /// @return The current administrator of this contract. function getAdmin() external view returns (address) { return _admin; } /// @dev Change the administrator to be `newAdmin`. /// @param newAdmin The address of the new administrator. function changeAdmin(address newAdmin) external { require(msg.sender == _admin, "ADMIN_ACCESS_DENIED"); emit AdminChanged(_admin, newAdmin); _admin = newAdmin; } }
//SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity 0.8.2; import "./WithAdmin.sol"; contract WithMinter is WithAdmin { address internal _minter; /// @dev Emits when the Minter address is changed /// @param oldMinter The previous Minter address /// @param newMinter The new Minter address event MinterChanged(address oldMinter, address newMinter); modifier onlyMinter() { require(msg.sender == _minter, "MINTER_ACCESS_DENIED"); _; } /// @dev Get the current minter of this contract. /// @return The current minter of this contract. function getMinter() external view returns (address) { return _minter; } /// @dev Change the minter to be `newMinter`. /// @param newMinter The address of the new minter. function changeMinter(address newMinter) external onlyAdmin() { emit MinterChanged(_minter, newMinter); _minter = newMinter; } }
//SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity 0.8.2; import "./WithAdmin.sol"; contract WithSuperOperators is WithAdmin { mapping(address => bool) internal _superOperators; event SuperOperator(address superOperator, bool enabled); /// @notice Enable or disable the ability of `superOperator` to transfer tokens of all (superOperator rights). /// @param superOperator address that will be given/removed superOperator right. /// @param enabled set whether the superOperator is enabled or disabled. function setSuperOperator(address superOperator, bool enabled) external { require(msg.sender == _admin, "only admin is allowed to add super operators"); _superOperators[superOperator] = enabled; emit SuperOperator(superOperator, enabled); } /// @notice check whether address `who` is given superOperator rights. /// @param who The address to query. /// @return whether the address has superOperator rights. function isSuperOperator(address who) public view returns (bool) { return _superOperators[who]; } }
pragma solidity ^0.8.0; import "@openzeppelin/contracts-0.8/utils/structs/EnumerableSet.sol"; library EnumerableMap { using EnumerableSet for EnumerableSet.UintSet; struct Map { // Storage of keys EnumerableSet.UintSet _keys; mapping(uint256 => uint256) _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( Map storage map, uint256 key, uint256 value ) private 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(Map storage map, uint256 key) private 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(Map storage map, uint256 key) private view returns (bool) { return map._keys.contains(key); } /** * @dev Returns the number of key-value pairs in the map. O(1). */ function _length(Map storage map) private 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(Map storage map, uint256 index) private view returns (uint256, uint256) { uint256 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(Map storage map, uint256 key) private view returns (bool, uint256) { uint256 value = map._values[key]; if (value == uint256(0)) { return (_contains(map, key), uint256(0)); } else { return (true, value); } } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function _get(Map storage map, uint256 key) private view returns (uint256) { uint256 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( Map storage map, uint256 key, string memory errorMessage ) private view returns (uint256) { uint256 value = map._values[key]; require(value != 0 || _contains(map, key), errorMessage); return value; } struct UintToUintMap { EnumerableMap.Map _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, uint256(key), uint256(value)); } /** * @dev Removes a value from a set. 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, uint256(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, uint256(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 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(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) { (uint256 key, uint256 value) = _at(map._inner, index); return (key, value); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. * * _Available since v3.4._ */ function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) { (bool success, uint256 value) = _tryGet(map._inner, uint256(key)); return (success, 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, 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, key, errorMessage)); } }
//SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity 0.8.2; interface IAssetToken { function mint( address creator, uint40 packId, bytes32 hash, uint256 supply, uint8 rarity, address owner, bytes calldata data ) external returns (uint256 id); function mintMultiple( address creator, uint40 packId, bytes32 hash, uint256[] calldata supplies, bytes calldata rarityPack, address owner, bytes calldata data ) external returns (uint256[] memory ids); // fails on non-NFT or nft who do not have collection (was a mistake) function collectionOf(uint256 id) external view returns (uint256); function balanceOf(address owner, uint256 id) external view returns (uint256); // return true for Non-NFT ERC1155 tokens which exists function isCollection(uint256 id) external view returns (bool); function collectionIndexOf(uint256 id) external view returns (uint256); function extractERC721From( address sender, uint256 id, address to ) external returns (uint256 newId); function transferFrom( address from, address to, uint256 id ) external; function safeTransferFrom( address from, address to, uint256 id ) external; function safeTransferFrom( address from, address to, uint256 id, uint256 value, bytes calldata data ) external; function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, bytes calldata data ) external; function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external; function isSuperOperator(address who) external view returns (bool); }
//SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity 0.8.2; /// @dev Note: The ERC-165 identifier for this interface is 0x5e8bf644. interface IERC721MandatoryTokenReceiver { function onERC721BatchReceived( address operator, address from, uint256[] calldata ids, bytes calldata data ) external returns (bytes4); // needs to return 0x4b808c46 function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); // needs to return 0x150b7a02 // needs to implements EIP-165 // function supportsInterface(bytes4 interfaceId) // external // view // returns (bool); }
//SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity 0.8.2; /// @title Interface for the Game token interface IGameToken { struct GameData { uint256[] assetIdsToRemove; uint256[] assetAmountsToRemove; uint256[] assetIdsToAdd; uint256[] assetAmountsToAdd; bytes32 uri; // ipfs hash (without the prefix, assume cidv1 folder) uint256 exactNumOfLandsRequired; } function createGame( address from, address to, GameData calldata creation, address editor, uint64 subId ) external returns (uint256 id); function burn(uint256 gameId) external; function burnFrom(address from, uint256 gameId) external; function recoverAssets( address from, address to, uint256 gameId, uint256[] calldata assetIds ) external; function burnAndRecover( address from, address to, uint256 gameId, uint256[] calldata assetIds ) external; function updateGame( address from, uint256 gameId, GameData calldata update ) external returns (uint256); function getAssetBalances(uint256 gameId, uint256[] calldata assetIds) external view returns (uint256[] calldata); function getExactNumOfLandsRequired(uint256 gameId) external view returns (uint256); function setGameEditor( address gameCreator, address editor, bool isEditor ) external; function isGameEditor(address gameOwner, address editor) external view returns (bool isEditor); function creatorOf(uint256 id) external view returns (address); function transferCreatorship( uint256 gameId, address sender, address to ) external; function name() external pure returns (string memory); function symbol() external pure returns (string memory); function tokenURI(uint256 gameId) external returns (string memory uri); function onERC1155Received( address operator, address, /*from*/ uint256, /*id*/ uint256, /*value*/ bytes calldata /*data*/ ) external view returns (bytes4); function onERC1155BatchReceived( address operator, address, /*from*/ uint256[] calldata, /*ids*/ uint256[] calldata, /*values*/ bytes calldata /*data*/ ) external view returns (bytes4); }
//SPDX-License-Identifier: MIT pragma solidity 0.8.2; interface LandToken { function batchTransferQuad( address from, address to, uint256[] calldata sizes, uint256[] calldata xs, uint256[] calldata ys, bytes calldata data ) external; function transferQuad( address from, address to, uint256 size, uint256 x, uint256 y, bytes calldata data ) external; function batchTransferFrom( address from, address to, uint256[] calldata ids, bytes calldata data ) external; function getX(uint256 id) external view returns (uint256); function getY(uint256 id) external view returns (uint256); }
//SPDX-License-Identifier: MIT // solhint-disable code-complexity pragma solidity 0.8.2; import "../common/BaseWithStorage/ImmutableERC721.sol"; import "../common/interfaces/ILandToken.sol"; import "../Game/GameBaseToken.sol"; import "../common/interfaces/IERC721MandatoryTokenReceiver.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "../common/Libraries/UintToUintMap.sol"; import "../common/BaseWithStorage/WithMinter.sol"; import "@openzeppelin/contracts-0.8/utils/structs/EnumerableSet.sol"; /// @dev An updated Estate Token contract using a simplified verison of LAND with no Quads contract EstateBaseToken is ImmutableERC721, Initializable, WithMinter { using EnumerableMap for EnumerableMap.UintToUintMap; using EnumerableSet for EnumerableSet.UintSet; uint8 internal constant OWNER = 0; uint8 internal constant ADD = 1; uint8 internal constant BREAK = 2; uint8 internal constant WITHDRAWAL = 3; uint16 internal constant GRID_SIZE = 408; uint64 internal _nextId; // max uint64 = 18,446,744,073,709,551,615 mapping(uint256 => bytes32) internal _metaData; // estates key = storageId // EnumerableMap.UintToUintMap keys = land ids // EnumerableMap.UintToUintMap values = game ids //map to a map mapping(uint256 => EnumerableMap.UintToUintMap) internal estates; // gamesToLands key = gameId, value = landIds mapping(uint256 => EnumerableSet.UintSet) internal gamesToLands; LandToken internal _land; GameBaseToken internal _gameToken; /// @param landIds LAND tokenIds added, Games added, Games removed, uri /// @param gameId Games added /// @param uri ipfs hash (without the prefix, assume cidv1 folder) struct EstateCRUDData { uint256[] landIds; uint256[] gameIds; bytes32 uri; } struct EstateData { uint256[] landIds; uint256[] gameIds; } /// @dev struct used for an update with multiple changes /// @dev gameIdsToReuse should be the first n gameIds from landAndGameAssociationsToRemove for minimum gas consumption struct UpdateEstateData { uint256[][] landAndGameAssociationsToAdd; uint256[][] landAndGameAssociationsToRemove; uint256[] gameIdsToReuse; uint256[] landIdsToAdd; uint256[] landIdsToRemove; bytes32 uri; } /// @dev Emits when a estate is updated. /// @param oldId The id of the previous erc721 ESTATE token. /// @param newId The id of the newly minted token. /// @param update The changes made to the Estate. event EstateTokenUpdated(uint256 indexed oldId, uint256 indexed newId, EstateCRUDData update); /// @dev Emits when a estate is updated. /// @param oldId The id of the previous erc721 ESTATE token. /// @param newId The id of the newly minted token. /// @param update The changes made to the Estate. event EstateTokenUpdatedII(uint256 indexed oldId, uint256 indexed newId, UpdateEstateData update); event EstateTokenUpdatedV3(uint256 indexed oldId, uint256 indexed newId, EstateData update); function initV1( address trustedForwarder, address admin, //address minter, LandToken land, GameBaseToken gameToken, uint8 chainIndex ) public initializer { _admin = admin; //_minter = minter; _gameToken = gameToken; _land = land; ERC721BaseToken.__ERC721BaseToken_initialize(chainIndex); } // @todo Add access-control: minter-only? could inherit WithMinter.sol, the game token creator is minter only /// @notice Create a new estate token with lands. /// @param from The address of the one creating the estate. /// @param to The address that will own the estate. /// @param creation The data to use to create the estate. function createEstate( address from, address to, EstateCRUDData calldata creation ) external returns (uint256) { //_check_authorized(from, ADD); require(creation.landIds.length == creation.gameIds.length, "DIFFERENT_LENGTH_LANDS_GAMES"); (uint256 estateId, uint256 storageId) = _mintEstate(from, to, _nextId++, 1, true); _metaData[storageId] = creation.uri; //_addLandsGames(from, storageId, creation.landIds, creation.gameIds); emit EstateTokenUpdated(0, estateId, creation); return estateId; } function updateEstateV2( address from, address to, uint256 estateId, UpdateEstateData memory update ) external returns (uint256) { _check_hasOwnerRights(from, estateId); uint256 storageId = _storageId(estateId); _metaData[storageId] = update.uri; //_check_authorized(from, ADD); uint256 gameToAddLength = update.landAndGameAssociationsToAdd[1].length; uint256 gameToRemoveLength = update.landAndGameAssociationsToRemove[1].length; uint256 gameIdsToReuseLength = update.gameIdsToReuse.length; /** add lands */ //what if there are no lands? _addLands(storageId, from, update.landIdsToAdd); /** remove association*/ if (gameToRemoveLength > 0) { require( gameToRemoveLength == update.landAndGameAssociationsToRemove[0].length, "DIFFERENT_LENGTH_LANDS_GAMES" ); require(update.gameIdsToReuse.length <= gameToAddLength, "GAMES_TO_REUSE_MUST_BE_PRESENT_IN_GAMES_TO_ADD"); require( update.gameIdsToReuse.length < gameToRemoveLength, "GAMES_TO_REUSE_MUST_BE_PRESENT_IN_GAMES_TO_REMOVE" ); for (uint256 i = 0; i < gameIdsToReuseLength; i++) { require( update.gameIdsToReuse[i] == update.landAndGameAssociationsToAdd[1][i], "GAMES_TO_REUSE_MUST_BE_PRESENT_IN_GAMES_TO_ADD" ); } uint256 newLength = gameToRemoveLength - gameIdsToReuseLength; uint256[] memory gamesToTransfer = new uint256[](newLength); for (uint256 i = gameIdsToReuseLength; i < gameToRemoveLength; i++) { gamesToTransfer[i - gameIdsToReuseLength] = update.landAndGameAssociationsToRemove[1][i]; } //there's a problem here, we're sending 0 games _removeGamesOfLands(from, storageId, update.landAndGameAssociationsToRemove[1], gamesToTransfer); } /** add association*/ if (gameToAddLength > 0) { require(gameToAddLength == update.landAndGameAssociationsToAdd[0].length, "DIFFERENT_LENGTH_LANDS_GAMES"); _addLandsGamesAssociation( from, storageId, update.landAndGameAssociationsToAdd[0], update.landAndGameAssociationsToAdd[1] ); } /** remove lands */ _removeLands(storageId, from, update.landIdsToRemove, false); uint256 newId = _incrementTokenVersion(to, estateId); EstateData memory estateState = getEstateData(storageId); emit EstateTokenUpdatedII(estateId, newId, update); } function _addLandsGames( address sender, uint256 storageId, uint256[] memory landIdsToAdd, uint256[] memory gameIds ) internal { require(landIdsToAdd.length > 0, "EMPTY_LAND_IDS_ARRAY"); //(uint256[] memory sizes, uint256[] memory xs, uint256[] memory ys) = _separateId(landIdsToAdd); //_land.batchTransferQuad(sender, address(this), sizes, xs, ys, ""); _land.batchTransferFrom(sender, address(this), landIdsToAdd, ""); _addLandsGamesAssociation(sender, storageId, landIdsToAdd, gameIds); } function _addLandsGamesAssociation( address sender, uint256 storageId, uint256[] memory landIds, uint256[] memory gameIds ) internal { //this was assuming that n lands = n games uint256[] memory gamesToAdd = new uint256[](gameIds.length); for (uint256 i = 0; i < landIds.length; i++) { uint256 gameId = gameIds[i]; (bool occupied, uint256 key) = estates[storageId].tryGet(landIds[i]); require( (/* !occupied && */ key == 0), "LAND_ALREADY_OCCUPIED" ); estates[storageId].set(landIds[i], gameId); gamesToLands[gameId].add(landIds[i]); if (gameId != 0) { if (gameIds.length > 1) { if ((i == 0 || gameId != gameIds[i - 1]) && _gameToken.ownerOf(gameId) != address(this)) { gamesToAdd[i] = gameId; } } else { if (_gameToken.ownerOf(gameId) != address(this)) { gamesToAdd[i] = gameId; } } } } if (gamesToAdd.length > 0) { for (uint256 i = 0; i < gamesToAdd.length; i++) {} _gameToken.batchTransferFrom(sender, address(this), gamesToAdd, ""); } } function _removeGamesOfLands( address from, uint256 storageId, uint256[] memory gameAssociationsToRemove, uint256[] memory gameIdsToRemove ) internal { uint256[] memory landsFromGames; for (uint256 i = 0; i < gameAssociationsToRemove.length; i++) { landsFromGames = getLandsForGame(gameAssociationsToRemove[i]); delete (gamesToLands[gameAssociationsToRemove[i]]); for (uint256 j = 0; j < landsFromGames.length; j++) { estates[storageId].set(landsFromGames[j], 0); } } _gameToken.batchTransferFrom(address(this), from, gameIdsToRemove, ""); } function _addLands( uint256 storageId, address from, uint256[] memory landIdsToAdd ) internal { uint256 len = landIdsToAdd.length; for (uint256 i = 0; i < len; i++) { estates[storageId].set(landIdsToAdd[i], 0); } _land.batchTransferFrom(from, address(this), landIdsToAdd, ""); } function _removeLands( uint256 storageId, address from, uint256[] memory landIdsToRemove, bool isBurned ) internal { uint256 len = landIdsToRemove.length; for (uint256 i = 0; i < len; i++) { (bool occupied, uint256 key) = estates[storageId].tryGet(landIdsToRemove[i]); require( /* !occupied */ isBurned || key == 0, "GAME_STILL_HOLDS_A_LAND" ); require(estates[storageId].remove(landIdsToRemove[i]), "LAND_DOES_NOT_EXIST"); } _land.batchTransferFrom(address(this), from, landIdsToRemove, ""); } /// @notice Burns token `id`. /// @param id The token which will be burnt. function burn(uint256 id) public override { address sender = _msgSender(); //_check_authorized(sender, BREAK); _check_hasOwnerRights(sender, id); _burn(sender, _ownerOf(id), id); } /// @notice Burn token`id` from `from`. /// @param from address whose token is to be burnt. /// @param id The token which will be burnt. function burnFrom(address from, uint256 id) external override { require(from != address(uint160(0)), "NOT_FROM_ZERO_ADDRESS"); (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id); require(owner != address(uint160(0)), "NONEXISTENT_TOKEN"); address msgSender = _msgSender(); require( msgSender == from || (operatorEnabled && _operators[id] == msgSender) || _superOperators[msgSender] || _operatorsForAll[from][msgSender], "UNAUTHORIZED_BURN" ); _burn(from, owner, id); } /// @notice Used to recover Land tokens from a burned estate. /// Note: Implemented separately from burn to avoid hitting the block gas-limit if estate has too many lands. /// @param sender The sender of the request. // / @param to The recipient of the Land tokens. // / @param num The number of Lands to transfer. /// @param estateId The estate to recover lands from. function transferFromBurnedEstate( address sender, address to, uint256 estateId, EstateData calldata associatioToRetrieve ) public { require(isBurned(estateId), "ASSET_NOT_BURNED"); require(sender != address(this), "NOT_FROM_THIS"); uint256 storageId = _storageId(estateId); address msgSender = _msgSender(); require(msgSender == sender || _superOperators[msgSender], "NOT_AUTHORIZED"); _check_withdrawal_authorized(sender, estateId); //_removeLandsGames(to, estateId, landsToRemove); _removeGamesOfLands(to, estateId, associatioToRetrieve.gameIds, associatioToRetrieve.gameIds); _removeLands(storageId, to, associatioToRetrieve.landIds, true); } function getEstateData(uint256 estateId) public view returns (EstateData memory) { uint256 storageId = _storageId(estateId); uint256 length = estates[storageId].length(); uint256[] memory landIds = new uint256[](length); uint256[] memory gameIds = new uint256[](length); //if (!isBurned(estateId)) { for (uint256 i = 0; i < length; i++) { (uint256 landId, uint256 gameId) = estates[storageId].at(i); landIds[i] = landId; gameIds[i] = gameId; } //} return EstateData({landIds: landIds, gameIds: gameIds}); } function getLandsForGame(uint256 gameId) public view returns (uint256[] memory) { uint256[] memory landIds = new uint256[](gamesToLands[gameId].length()); for (uint256 i = 0; i < gamesToLands[gameId].length(); i++) { landIds[i] = gamesToLands[gameId].at(i); } return landIds; //gamesToLands[gameId].values(); } /// @notice Return the name of the token contract. /// @return The name of the token contract. function name() external pure returns (string memory) { return "The Sandbox: ESTATE token"; } /// @notice Get the symbol of the token contract. /// @return the symbol of the token contract. function symbol() external pure returns (string memory) { return "ESTATE"; } /// @notice Return the URI of a specific token. /// @param id The id of the token. /// @return uri The URI of the token metadata. function tokenURI(uint256 id) public view returns (string memory uri) { require(_ownerOf(id) != address(0), "BURNED_OR_NEVER_MINTED"); uint256 immutableId = _storageId(id); return _toFullURI(_metaData[immutableId]); } function onERC721BatchReceived( address, // operator, address, // from, uint256[] calldata, // ids, bytes calldata // data ) external pure returns (bytes4) { revert("please call createEstate or updateEstate functions"); } function onERC721Received( address, // operator, address, // from, uint256, // tokenId, bytes calldata // data ) external pure returns (bytes4) { revert("please call createEstate or updateEstate functions"); } // ////////////////////////////////////////////////////////////////////////////////////////////////////// //this is a function to separate land ids into its x and y coordianates function _separateId( uint256[] memory landIds //sizes are always 1 ) internal returns ( uint256[] memory, uint256[] memory, uint256[] memory ) { uint256 numLds = landIds.length; uint256[] memory sizes = new uint256[](numLds); uint256[] memory xs = new uint256[](numLds); uint256[] memory ys = new uint256[](numLds); for (uint256 i = 0; i < numLds; i++) { sizes[i] = 1; xs[i] = _land.getX(landIds[i]); ys[i] = _land.getY(landIds[i]); } return (sizes, xs, ys); } /// @dev used to increment the version in a tokenId by burning the original and reminting a new token. Mappings to token-specific data are preserved via the storageId mechanism. /// @param from The address of the token owner. /// @param estateId The tokenId to increment. /// @return the version-incremented tokenId. function _incrementTokenVersion(address from, uint256 estateId) internal returns (uint256) { address originalCreator = address(uint160(estateId / CREATOR_OFFSET_MULTIPLIER)); uint64 subId = uint64(estateId / SUBID_MULTIPLIER); uint16 version = uint16(estateId); version++; address owner = _ownerOf(estateId); if (from == owner) { _burn(from, owner, estateId); } (uint256 newId, ) = _mintEstate(originalCreator, owner, subId, version, false); address newOwner = _ownerOf(newId); require(owner == newOwner, "NOT_OWNER"); return newId; } /// @dev Create a new (or incremented) estateId and associate it with an owner. /// @param from The address of one creating the Estate. /// @param to The address of the Estate owner. /// @param subId The id to use when generating the new estateId. /// @param version The version number part of the estateId. /// @param isCreation Whether this is a brand new Estate (as opposed to an update). /// @return id The newly created estateId. /// @return storageId The staorage Id for the token. function _mintEstate( address from, address to, uint64 subId, uint16 version, bool isCreation ) internal returns (uint256, uint256 storageId) { require(to != address(uint160(0)), "CAN'T_SEND_TO_ZERO_ADDRESS"); uint16 idVersion; uint256 estateId; uint256 strgId; if (isCreation) { idVersion = 1; estateId = _generateTokenId(from, subId, _chainIndex, idVersion); strgId = _storageId(estateId); require(_owners[strgId] == 0, "STORAGE_ID_REUSE_FORBIDDEN"); } else { idVersion = version; estateId = _generateTokenId(from, subId, _chainIndex, idVersion); strgId = _storageId(estateId); } _owners[strgId] = (uint256(idVersion) << 200) + uint256(uint160(to)); _numNFTPerAddress[to]++; emit Transfer(address(0), to, estateId); return (estateId, strgId); } function _check_authorized(address sender, uint8 action) internal view { require(sender != address(uint160(0)), "SENDER_IS_ZERO_ADDRESS"); address msgSender = _msgSender(); if (action == ADD) { address minter = _minter; require(msgSender == minter || msgSender == sender, "UNAUTHORIZED_ADD"); } else { require(msgSender == sender, "NOT_AUTHORIZED"); } } function _check_hasOwnerRights(address sender, uint256 estateId) internal view { (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(estateId); require(owner != address(uint160(0)), "TOKEN_DOES_NOT_EXIST"); address msgSender = _msgSender(); require( owner == sender || _superOperators[msgSender] || _operatorsForAll[sender][msgSender] || (operatorEnabled && _operators[estateId] == msgSender), "NOT_APPROVED" ); } function _encode( uint16 x, uint16 y, uint8 size ) internal pure returns (uint24) { return uint24(size) * uint24(2**18) + (uint24(x) + uint24(y) * GRID_SIZE); } function _decode(uint24 data) internal pure returns ( uint16 x, uint16 y, uint8 size ) { size = uint8(data / (2**18)); y = uint16((data % (2**18)) / GRID_SIZE); x = uint16(data % GRID_SIZE); } /// @dev Get the a full URI string for a given hash + gameId. /// @param hash The 32 byte IPFS hash. /// @return The URI string. function _toFullURI(bytes32 hash) internal pure override returns (string memory) { return string(abi.encodePacked("ipfs://bafybei", hash2base32(hash), "/", "estate.json")); } function isItInArray(uint256 id, uint256[] memory landIds) public pure returns (bool) { uint256 size = landIds.length; bool flag = false; for (uint256 i = 0; i < size; i++) { if (landIds[i] == id) { flag = true; break; } } return flag; } // solhint-enable code-complexity }
//SPDX-License-Identifier: MIT pragma solidity 0.8.2; import "../../estate/EstateBaseToken.sol"; // solhint-disable-next-line no-empty-blocks contract ChildEstateTokenV1 is EstateBaseToken { }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 2000 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newId","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"},{"internalType":"uint256[]","name":"gameIds","type":"uint256[]"},{"internalType":"bytes32","name":"uri","type":"bytes32"}],"indexed":false,"internalType":"struct EstateBaseToken.EstateCRUDData","name":"update","type":"tuple"}],"name":"EstateTokenUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newId","type":"uint256"},{"components":[{"internalType":"uint256[][]","name":"landAndGameAssociationsToAdd","type":"uint256[][]"},{"internalType":"uint256[][]","name":"landAndGameAssociationsToRemove","type":"uint256[][]"},{"internalType":"uint256[]","name":"gameIdsToReuse","type":"uint256[]"},{"internalType":"uint256[]","name":"landIdsToAdd","type":"uint256[]"},{"internalType":"uint256[]","name":"landIdsToRemove","type":"uint256[]"},{"internalType":"bytes32","name":"uri","type":"bytes32"}],"indexed":false,"internalType":"struct EstateBaseToken.UpdateEstateData","name":"update","type":"tuple"}],"name":"EstateTokenUpdatedII","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newId","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"},{"internalType":"uint256[]","name":"gameIds","type":"uint256[]"}],"indexed":false,"internalType":"struct EstateBaseToken.EstateData","name":"update","type":"tuple"}],"name":"EstateTokenUpdatedV3","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldMinter","type":"address"},{"indexed":false,"internalType":"address","name":"newMinter","type":"address"}],"name":"MinterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"superOperator","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"SuperOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approveFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"batchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"changeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMinter","type":"address"}],"name":"changeMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"},{"internalType":"uint256[]","name":"gameIds","type":"uint256[]"},{"internalType":"bytes32","name":"uri","type":"bytes32"}],"internalType":"struct EstateBaseToken.EstateCRUDData","name":"creation","type":"tuple"}],"name":"createEstate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"estateId","type":"uint256"}],"name":"getEstateData","outputs":[{"components":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"},{"internalType":"uint256[]","name":"gameIds","type":"uint256[]"}],"internalType":"struct EstateBaseToken.EstateData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gameId","type":"uint256"}],"name":"getLandsForGame","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMinter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getStorageId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTrustedForwarder","outputs":[{"internalType":"address","name":"trustedForwarder","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trustedForwarder","type":"address"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"contract LandToken","name":"land","type":"address"},{"internalType":"contract GameBaseToken","name":"gameToken","type":"address"},{"internalType":"uint8","name":"chainIndex","type":"uint8"}],"name":"initV1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"isOperator","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"estateId","type":"uint256"}],"name":"isBurned","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256[]","name":"landIds","type":"uint256[]"}],"name":"isItInArray","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"isSuperOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"onERC721BatchReceived","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":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAllFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"superOperator","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setSuperOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"id","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"estateId","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"},{"internalType":"uint256[]","name":"gameIds","type":"uint256[]"}],"internalType":"struct EstateBaseToken.EstateData","name":"associatioToRetrieve","type":"tuple"}],"name":"transferFromBurnedEstate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"estateId","type":"uint256"},{"components":[{"internalType":"uint256[][]","name":"landAndGameAssociationsToAdd","type":"uint256[][]"},{"internalType":"uint256[][]","name":"landAndGameAssociationsToRemove","type":"uint256[][]"},{"internalType":"uint256[]","name":"gameIdsToReuse","type":"uint256[]"},{"internalType":"uint256[]","name":"landIdsToAdd","type":"uint256[]"},{"internalType":"uint256[]","name":"landIdsToRemove","type":"uint256[]"},{"internalType":"bytes32","name":"uri","type":"bytes32"}],"internalType":"struct EstateBaseToken.UpdateEstateData","name":"update","type":"tuple"}],"name":"updateEstateV2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b506150b1806100206000396000f3fe608060405234801561001057600080fd5b50600436106102925760003560e01c8063654b748a11610160578063a22cb465116100d8578063db44fe071161008c578063eeb5a5d111610071578063eeb5a5d114610604578063f366751714610617578063f56baa0e1461063057610292565b8063db44fe07146105c1578063e985e9c5146105f157610292565b8063b88d4fde116100bd578063b88d4fde1461058a578063c87b56dd1461059d578063ce1b815f146105b057610292565b8063a22cb46514610564578063ac9fe4211461057757610292565b80638f2839701161012f57806395d89b411161011457806395d89b41146105055780639d7a3b871461053e5780639df4c3bf1461055157610292565b80638f283970146104d25780639381da6e146104e557610292565b8063654b748a1461046f5780636e9960c31461049b57806370a08231146104ac57806379cc6790146104bf57610292565b806323b872dd1161020e57806342842e0e116101c25780634b808c46116101a75780634b808c461461042c578063572b6c051461043a5780636352211e1461045c57610292565b806342842e0e1461040657806342966c681461041957610292565b80632b991746116101f35780632b991746146103cd5780632c4d4d18146103e057806333b47e58146103f357610292565b806323b872dd146103a757806328cfbd46146103ba57610292565b80630a148eb31161026557806315ddc5351161024a57806315ddc5351461035357806321ab0c711461036657806322e695391461038757610292565b80630a148eb314610314578063150b7a021461032757610292565b806301ffc9a71461029757806306fdde03146102bf578063081812fc146102d4578063095ea7b3146102ff575b600080fd5b6102aa6102a53660046148b7565b610643565b60405190151581526020015b60405180910390f35b6102c76106ae565b6040516102b69190614ba6565b6102e76102e23660046148ef565b6106e6565b6040516001600160a01b0390911681526020016102b6565b61031261030d36600461488c565b610785565b005b6103126103223660046146b8565b6108d0565b61033a61033536600461458b565b610b10565b6040516001600160e01b031990911681526020016102b6565b61031261036136600461436b565b610b81565b6103796103743660046148ef565b610bf3565b6040519081526020016102b6565b61039a6103953660046148ef565b610c02565b6040516102b69190614b93565b6103126103b536600461454b565b610cec565b6103126103c836600461436b565b610dba565b6103126103db36600461454b565b610e2f565b6103126103ee3660046142fb565b610fc7565b610312610401366004614470565b6110b0565b61031261041436600461454b565b611208565b6103126104273660046148ef565b611223565b61033a61033536600461436b565b6102aa6104483660046142fb565b6002546001600160a01b0390811691161490565b6102e761046a3660046148ef565b611250565b6102aa61047d3660046142fb565b6001600160a01b031660009081526001602052604090205460ff1690565b6000546001600160a01b03166102e7565b6103796104ba3660046142fb565b6112b3565b6103126104cd36600461488c565b611327565b6103126104e03660046142fb565b6114db565b6104f86104f33660046148ef565b6115ab565b6040516102b69190614c1d565b60408051808201909152600681527f455354415445000000000000000000000000000000000000000000000000000060208201526102c7565b6102aa61054c366004614907565b611743565b61037961055f366004614726565b6117a8565b610312610572366004614858565b611d6f565b610312610585366004614858565b611d81565b6103126105983660046145fc565b611e64565b6102c76105ab3660046148ef565b611ef1565b6002546001600160a01b03166102e7565b6102aa6105cf3660046148ef565b63ffffffff1916600090815260046020526040902054600160a01b9081161490565b6102aa6105ff366004614333565b611f7c565b61031261061236600461442a565b611fce565b6102e7600754630100000090046001600160a01b031690565b61037961063e3660046144e5565b6120bf565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614806106a657507f80ac58cd000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b90505b919050565b60408051808201909152601981527f5468652053616e64626f783a2045535441544520746f6b656e0000000000000060208201525b90565b60008060006106f4846121e1565b90925090506001600160a01b0382166107545760405162461bcd60e51b815260206004820152601160248201527f4e4f4e4558495354454e545f544f4b454e00000000000000000000000000000060448201526064015b60405180910390fd5b801561077a575050506000818152600660205260409020546001600160a01b03166106a9565b6000925050506106a9565b63ffffffff198116600090815260046020526040812054906107a683612226565b905060006107b261227f565b90506001600160a01b03821661080a5760405162461bcd60e51b815260206004820152601160248201527f4e4f4e4558495354454e545f544f4b454e000000000000000000000000000000604482015260640161074b565b806001600160a01b0316826001600160a01b0316148061084257506001600160a01b03811660009081526001602052604090205460ff165b8061087257506001600160a01b0380831660009081526005602090815260408083209385168352929052205460ff165b6108be5760405162461bcd60e51b815260206004820152601560248201527f554e415554484f52495a45445f415050524f56414c0000000000000000000000604482015260640161074b565b6108c98386866122c9565b5050505050565b63ffffffff198216600090815260046020526040902054600160a01b9081161461093c5760405162461bcd60e51b815260206004820152601060248201527f41535345545f4e4f545f4255524e454400000000000000000000000000000000604482015260640161074b565b6001600160a01b0384163014156109955760405162461bcd60e51b815260206004820152600d60248201527f4e4f545f46524f4d5f5448495300000000000000000000000000000000000000604482015260640161074b565b63ffffffff19821660006109a761227f565b9050856001600160a01b0316816001600160a01b031614806109e157506001600160a01b03811660009081526001602052604090205460ff165b610a2d5760405162461bcd60e51b815260206004820152600e60248201527f4e4f545f415554484f52495a4544000000000000000000000000000000000000604482015260640161074b565b610a37868561237f565b610abf8585610a496020870187614cff565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610a88925050506020880188614cff565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061244c92505050565b610b088286610ace8680614cff565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250600192506125c3915050565b505050505050565b60405162461bcd60e51b815260206004820152603260248201527f706c656173652063616c6c20637265617465457374617465206f72207570646160448201527f74654573746174652066756e6374696f6e730000000000000000000000000000606482015260009060840161074b565b610b08868686868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020601f8a0181900481028201810190925288815292508891508790819084018382808284376000920182905250925061275b915050565b600063ffffffff1982166106a6565b6000818152600a6020526040812060609190610c1d90612b5f565b67ffffffffffffffff811115610c4357634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610c6c578160200160208202803683370190505b50905060005b6000848152600a60205260409020610c8990612b5f565b811015610ce5576000848152600a60205260409020610ca89082612b69565b828281518110610cc857634e487b7160e01b600052603260045260246000fd5b602090810291909101015280610cdd81614fc1565b915050610c72565b5092915050565b610cf7838383612b75565b50610d03838383612d8d565b6001600160a01b0382163b15158015610d415750610d41827f5e8bf64400000000000000000000000000000000000000000000000000000000612e52565b15610db557610d69610d5161227f565b84848460405180602001604052806000815250612f19565b610db55760405162461bcd60e51b815260206004820152601860248201527f4552433732315f5452414e534645525f52454a45435445440000000000000000604482015260640161074b565b505050565b610b08868686868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020601f8a0181900481028201810190925288815292508891508790819084018382808284376000920191909152506001925061275b915050565b63ffffffff19811660009081526004602052604081205490610e4f61227f565b90506001600160a01b038516610ea75760405162461bcd60e51b815260206004820152601360248201527f5a45524f5f414444524553535f53454e44455200000000000000000000000000604482015260640161074b565b846001600160a01b0316816001600160a01b03161480610edf57506001600160a01b03811660009081526001602052604090205460ff165b80610f0f57506001600160a01b0380861660009081526005602090815260408083209385168352929052205460ff165b610f5b5760405162461bcd60e51b815260206004820152601560248201527f554e415554484f52495a45445f415050524f56414c0000000000000000000000604482015260640161074b565b846001600160a01b0316826001600160a01b031614610fbc5760405162461bcd60e51b815260206004820152601060248201527f4f574e45525f4e4f545f53454e44455200000000000000000000000000000000604482015260640161074b565b6108c98285856122c9565b6000546001600160a01b031633146110215760405162461bcd60e51b815260206004820152600a60248201527f41444d494e5f4f4e4c5900000000000000000000000000000000000000000000604482015260640161074b565b600754604080516001600160a01b0363010000009093048316815291831660208301527f3b0007eb941cf645526cbb3a4fdaecda9d28ce4843167d9263b536a1f1edc0f6910160405180910390a1600780546001600160a01b039092166301000000027fffffffffffffffffff0000000000000000000000000000000000000000ffffff909216919091179055565b60075462010000900460ff166110d157600754610100900460ff16156110d5565b303b155b6111475760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161074b565b60075462010000900460ff1615801561119457600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff62ff0000199091166201000017166101001790555b6000805473ffffffffffffffffffffffffffffffffffffffff199081166001600160a01b0388811691909117909255600c80548216868416179055600b80549091169186169190911790556007805460ff191660ff84161790558015610b08576007805462ff000019169055505050505050565b610db583838360405180602001604052806000815250611e64565b600061122d61227f565b90506112398183612fd8565b61124c8161124684612226565b8461312b565b5050565b600061125b82612226565b90506001600160a01b0381166106a95760405162461bcd60e51b815260206004820152601160248201527f4e4f4e4558495354414e545f544f4b454e000000000000000000000000000000604482015260640161074b565b60006001600160a01b03821661130b5760405162461bcd60e51b815260206004820152601260248201527f5a45524f5f414444524553535f4f574e45520000000000000000000000000000604482015260640161074b565b506001600160a01b031660009081526003602052604090205490565b6001600160a01b03821661137d5760405162461bcd60e51b815260206004820152601560248201527f4e4f545f46524f4d5f5a45524f5f414444524553530000000000000000000000604482015260640161074b565b600080611389836121e1565b90925090506001600160a01b0382166113e45760405162461bcd60e51b815260206004820152601160248201527f4e4f4e4558495354454e545f544f4b454e000000000000000000000000000000604482015260640161074b565b60006113ee61227f565b9050846001600160a01b0316816001600160a01b03161480611431575081801561143157506000848152600660205260409020546001600160a01b038281169116145b8061145457506001600160a01b03811660009081526001602052604090205460ff165b8061148457506001600160a01b0380861660009081526005602090815260408083209385168352929052205460ff165b6114d05760405162461bcd60e51b815260206004820152601160248201527f554e415554484f52495a45445f4255524e000000000000000000000000000000604482015260640161074b565b6108c985848661312b565b6000546001600160a01b031633146115355760405162461bcd60e51b815260206004820152601360248201527f41444d494e5f4143434553535f44454e49454400000000000000000000000000604482015260640161074b565b600054604080516001600160a01b03928316815291831660208301527f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f910160405180910390a16000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6040805180820190915260608082526020820152600063ffffffff1983166000818152600960205260408120919250906115e490613229565b905060008167ffffffffffffffff81111561160f57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611638578160200160208202803683370190505b50905060008267ffffffffffffffff81111561166457634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561168d578160200160208202803683370190505b50905060005b8381101561172857600085815260096020526040812081906116b59084613234565b91509150818584815181106116da57634e487b7160e01b600052603260045260246000fd5b6020026020010181815250508084848151811061170757634e487b7160e01b600052603260045260246000fd5b6020026020010181815250505050808061172090614fc1565b915050611693565b50604080518082019091529182526020820152949350505050565b805160009081805b8281101561179d578585828151811061177457634e487b7160e01b600052603260045260246000fd5b6020026020010151141561178b576001915061179d565b8061179581614fc1565b91505061174b565b509150505b92915050565b60006117b48584612fd8565b60a082015163ffffffff1984166000818152600860205260408120929092558351805191929160019081106117f957634e487b7160e01b600052603260045260246000fd5b60200260200101515190506000846020015160018151811061182b57634e487b7160e01b600052603260045260246000fd5b60200260200101515190506000856040015151905061184f848a8860600151613252565b8115611c1a57856020015160008151811061187a57634e487b7160e01b600052603260045260246000fd5b60200260200101515182146118d15760405162461bcd60e51b815260206004820152601c60248201527f444946464552454e545f4c454e4754485f4c414e44535f47414d455300000000604482015260640161074b565b82866040015151111561194c5760405162461bcd60e51b815260206004820152602e60248201527f47414d45535f544f5f52455553455f4d5553545f42455f50524553454e545f4960448201527f4e5f47414d45535f544f5f414444000000000000000000000000000000000000606482015260840161074b565b81866040015151106119c65760405162461bcd60e51b815260206004820152603160248201527f47414d45535f544f5f52455553455f4d5553545f42455f50524553454e545f4960448201527f4e5f47414d45535f544f5f52454d4f5645000000000000000000000000000000606482015260840161074b565b60005b81811015611ad4578651805160019081106119f457634e487b7160e01b600052603260045260246000fd5b60200260200101518181518110611a1b57634e487b7160e01b600052603260045260246000fd5b602002602001015187604001518281518110611a4757634e487b7160e01b600052603260045260246000fd5b602002602001015114611ac25760405162461bcd60e51b815260206004820152602e60248201527f47414d45535f544f5f52455553455f4d5553545f42455f50524553454e545f4960448201527f4e5f47414d45535f544f5f414444000000000000000000000000000000000000606482015260840161074b565b80611acc81614fc1565b9150506119c9565b506000611ae18284614f45565b905060008167ffffffffffffffff811115611b0c57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611b35578160200160208202803683370190505b509050825b84811015611bde578860200151600181518110611b6757634e487b7160e01b600052603260045260246000fd5b60200260200101518181518110611b8e57634e487b7160e01b600052603260045260246000fd5b6020026020010151828583611ba39190614f45565b81518110611bc157634e487b7160e01b600052603260045260246000fd5b602090810291909101015280611bd681614fc1565b915050611b3a565b50611c178b878a60200151600181518110611c0957634e487b7160e01b600052603260045260246000fd5b60200260200101518461244c565b50505b8215611cfc5785518051600090611c4157634e487b7160e01b600052603260045260246000fd5b6020026020010151518314611c985760405162461bcd60e51b815260206004820152601c60248201527f444946464552454e545f4c454e4754485f4c414e44535f47414d455300000000604482015260640161074b565b611cfc89858860000151600081518110611cc257634e487b7160e01b600052603260045260246000fd5b60200260200101518960000151600181518110611cef57634e487b7160e01b600052603260045260246000fd5b6020026020010151613318565b611d0d848a886080015160006125c3565b6000611d19898961372c565b90506000611d26866115ab565b905081897f9e7c7d8ddece27ce406d7f0d11566fca4d42b7f4a641c0ef4efa85e359c6e4a58a604051611d599190614c56565b60405180910390a3505050505050949350505050565b61124c611d7a61227f565b838361382e565b6000546001600160a01b03163314611e015760405162461bcd60e51b815260206004820152602c60248201527f6f6e6c792061646d696e20697320616c6c6f77656420746f206164642073757060448201527f6572206f70657261746f72730000000000000000000000000000000000000000606482015260840161074b565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527f44f92d27abdf4cfb6a7d712c3af68f3be086d4ca747ab802c36f67d6790060d8910160405180910390a15050565b611e6f848484612b75565b50611e7b848484612d8d565b6001600160a01b0383163b15611eeb57611e9f611e9661227f565b85858585612f19565b611eeb5760405162461bcd60e51b815260206004820152601860248201527f4552433732315f5452414e534645525f52454a45435445440000000000000000604482015260640161074b565b50505050565b60606000611efe83612226565b6001600160a01b03161415611f555760405162461bcd60e51b815260206004820152601660248201527f4255524e45445f4f525f4e455645525f4d494e54454400000000000000000000604482015260640161074b565b63ffffffff198216600081815260086020526040902054611f7590613904565b9392505050565b6001600160a01b03808316600090815260056020908152604080832093851683529290529081205460ff1680611f755750506001600160a01b031660009081526001602052604090205460ff16919050565b6001600160a01b0383166120245760405162461bcd60e51b815260206004820152601660248201527f496e76616c69642073656e646572206164647265737300000000000000000000604482015260640161074b565b600061202e61227f565b9050836001600160a01b0316816001600160a01b0316148061206857506001600160a01b03811660009081526001602052604090205460ff165b6120b45760405162461bcd60e51b815260206004820152601c60248201527f554e415554484f52495a45445f415050524f56455f464f525f414c4c00000000604482015260640161074b565b611eeb84848461382e565b60006120ce6020830183614cff565b90506120da8380614cff565b9050146121295760405162461bcd60e51b815260206004820152601c60248201527f444946464552454e545f4c454e4754485f4c414e44535f47414d455300000000604482015260640161074b565b60008061218586866007601781819054906101000a900467ffffffffffffffff168092919061215790614fdc565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550600180613935565b6000818152600860205260408082208189013590555192945090925083917f0e1331b3d93257377695e09c5f57e70594445e5b47ebdd513b8db11f7ce9ed7b906121d0908890614bb9565b60405180910390a350949350505050565b63ffffffff1981166000908152600460205260408120548190600160a01b80821614156122115760009250612215565b8092505b600160ff1b80821614915050915091565b63ffffffff1981166000908152600460205260408120548260c882901c63ffffffff16600160a01b808416148061226557508061ffff168261ffff1614155b1561227657600093505050506106a9565b50909392505050565b6002546000906001600160a01b03163314156122c257507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c6106e3565b50336106e3565b60006122d482612226565b90506001600160a01b0383166122f6576122f18285836000613af6565b612338565b6123038285836001613af6565b6000828152600660205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0385161790555b81836001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a450505050565b6001600160a01b0382166123d55760405162461bcd60e51b815260206004820152601360248201527f53454e4445525f5a45524f5f4144445245535300000000000000000000000000604482015260640161074b565b63ffffffff1981166000908152600460205260409020546001600160a01b0316826001600160a01b03161461124c5760405162461bcd60e51b815260206004820152601b60248201527f4c4153545f4f574e45525f4e4f545f455155414c5f53454e4445520000000000604482015260640161074b565b606060005b83518110156125555761248a84828151811061247d57634e487b7160e01b600052603260045260246000fd5b6020026020010151610c02565b9150600a60008583815181106124b057634e487b7160e01b600052603260045260246000fd5b602002602001015181526020019081526020016000206000808201600080820160006124dc91906141b0565b5050505060005b82518110156125425761252f83828151811061250f57634e487b7160e01b600052603260045260246000fd5b602090810291909101810151600089815260099092526040822091613b98565b508061253a81614fc1565b9150506124e3565b508061254d81614fc1565b915050612451565b50600c546040516315ddc53560e01b81526001600160a01b03909116906315ddc5359061258a90309089908790600401614b1d565b600060405180830381600087803b1580156125a457600080fd5b505af11580156125b8573d6000803e3d6000fd5b505050505050505050565b815160005b818110156127265760008061261f8684815181106125f657634e487b7160e01b600052603260045260246000fd5b6020026020010151600960008b8152602001908152602001600020613bad90919063ffffffff16565b91509150848061262d575080155b6126795760405162461bcd60e51b815260206004820152601760248201527f47414d455f5354494c4c5f484f4c44535f415f4c414e44000000000000000000604482015260640161074b565b6126c586848151811061269c57634e487b7160e01b600052603260045260246000fd5b6020026020010151600960008b8152602001908152602001600020613bbc90919063ffffffff16565b6127115760405162461bcd60e51b815260206004820152601360248201527f4c414e445f444f45535f4e4f545f455849535400000000000000000000000000604482015260640161074b565b5050808061271e90614fc1565b9150506125c8565b50600b546040516315ddc53560e01b81526001600160a01b03909116906315ddc5359061258a90309088908890600401614b1d565b600061276561227f565b90506000866001600160a01b0316826001600160a01b031614806127a157506001600160a01b03821660009081526001602052604090205460ff165b806127d157506001600160a01b0380881660009081526005602090815260408083209386168352929052205460ff165b90506001600160a01b0387166128295760405162461bcd60e51b815260206004820152601460248201527f4e4f545f46524f4d5f5a45524f41444452455353000000000000000000000000604482015260640161074b565b6001600160a01b03861661287f5760405162461bcd60e51b815260206004820152601260248201527f4e4f545f544f5f5a45524f414444524553530000000000000000000000000000604482015260640161074b565b845160005b8651811015612a3d5760008782815181106128af57634e487b7160e01b600052603260045260246000fd5b6020026020010151905080600014156128d557826128cc81614f88565b93505050612a2b565b6000806128e1836121e1565b915091508b6001600160a01b0316826001600160a01b0316146129465760405162461bcd60e51b815260206004820152601b60248201527f42415443485452414e5346455246524f4d5f4e4f545f4f574e45520000000000604482015260640161074b565b8580612973575080801561297357506000838152600660205260409020546001600160a01b038881169116145b6129bf5760405162461bcd60e51b815260206004820152600e60248201527f4e4f545f415554484f52495a4544000000000000000000000000000000000000604482015260640161074b565b6129e6836004600063ffffffff1983168152602001908152602001600020548d6000613af6565b828b6001600160a01b03168d6001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505b80612a3581614fc1565b915050612884565b50866001600160a01b0316886001600160a01b031614612ab2576001600160a01b03881660009081526003602052604081208054839290612a7f908490614f45565b90915550506001600160a01b03871660009081526003602052604081208054839290612aac908490614de3565b90915550505b6001600160a01b0387163b15158015612af757508380612af75750612af7877f5e8bf64400000000000000000000000000000000000000000000000000000000612e52565b15612b5557612b098389898989613bc8565b612b555760405162461bcd60e51b815260206004820152601e60248201527f4552433732315f42415443485f5452414e534645525f52454a45435445440000604482015260640161074b565b5050505050505050565b60006106a6825490565b6000611f758383613c87565b6000806000612b83846121e1565b915091506000612b9161227f565b90506001600160a01b038316612be95760405162461bcd60e51b815260206004820152601160248201527f4e4f4e4558495354454e545f544f4b454e000000000000000000000000000000604482015260640161074b565b866001600160a01b0316836001600160a01b031614612c4a5760405162461bcd60e51b815260206004820152601760248201527f434845434b5452414e534645525f4e4f545f4f574e4552000000000000000000604482015260640161074b565b6001600160a01b038616612ca05760405162461bcd60e51b815260206004820152601260248201527f4e4f545f544f5f5a45524f414444524553530000000000000000000000000000604482015260640161074b565b826001600160a01b0316816001600160a01b03161480612cd857506001600160a01b03811660009081526001602052604090205460ff165b80612d0857506001600160a01b0380881660009081526005602090815260408083209385168352929052205460ff165b80612d345750818015612d3457506000858152600660205260409020546001600160a01b038281169116145b612d805760405162461bcd60e51b815260206004820152601560248201527f554e415554484f52495a45445f5452414e534645520000000000000000000000604482015260640161074b565b5060019695505050505050565b6001600160a01b0383166000908152600360205260408120805491612db183614f88565b90915550506001600160a01b0382166000908152600360205260408120805491612dda83614fc1565b9190505550612e0c8160046000612df58563ffffffff191690565b815260200190815260200160002054846000613af6565b80826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b604080516001600160e01b031983166024808301919091528251808303909101815260449091018252602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a7000000000000000000000000000000000000000000000000000000001781528251935160008082529485948594909392908183858c612710fa955080519450505050609e5a11612f0557634e487b7160e01b600052600160045260246000fd5b828015612f0f5750815b9695505050505050565b600080846001600160a01b031663150b7a02888887876040518563ffffffff1660e01b8152600401612f4e9493929190614b61565b602060405180830381600087803b158015612f6857600080fd5b505af1158015612f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa091906148d3565b6001600160e01b0319167f150b7a02000000000000000000000000000000000000000000000000000000001491505095945050505050565b600080612fe4836121e1565b90925090506001600160a01b03821661303f5760405162461bcd60e51b815260206004820152601460248201527f544f4b454e5f444f45535f4e4f545f4558495354000000000000000000000000604482015260640161074b565b600061304961227f565b9050846001600160a01b0316836001600160a01b0316148061308357506001600160a01b03811660009081526001602052604090205460ff165b806130b357506001600160a01b0380861660009081526005602090815260408083209385168352929052205460ff165b806130df57508180156130df57506000848152600660205260409020546001600160a01b038281169116145b6108c95760405162461bcd60e51b815260206004820152600c60248201527f4e4f545f415050524f5645440000000000000000000000000000000000000000604482015260640161074b565b816001600160a01b0316836001600160a01b03161461318c5760405162461bcd60e51b815260206004820152600960248201527f4e4f545f4f574e45520000000000000000000000000000000000000000000000604482015260640161074b565b63ffffffff198116600160a01b6131a86001600160ff1b614f45565b6000838152600460209081526040808320805494909416949094179092556001600160a01b038716815260039091529081208054916131e683614f88565b909155505060405182906000906001600160a01b038716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a450505050565b60006106a682613d36565b60008080806132438686613d41565b909450925050505b9250929050565b805160005b818110156132b5576132a283828151811061328257634e487b7160e01b600052603260045260246000fd5b602090810291909101810151600088815260099092526040822091613b98565b50806132ad81614fc1565b915050613257565b50600b546040516315ddc53560e01b81526001600160a01b03909116906315ddc535906132ea90869030908790600401614b1d565b600060405180830381600087803b15801561330457600080fd5b505af1158015612b55573d6000803e3d6000fd5b6000815167ffffffffffffffff81111561334257634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561336b578160200160208202803683370190505b50905060005b83518110156136d157600083828151811061339c57634e487b7160e01b600052603260045260246000fd5b602002602001015190506000806133cc8785815181106125f657634e487b7160e01b600052603260045260246000fd5b91509150806000146134205760405162461bcd60e51b815260206004820152601560248201527f4c414e445f414c52454144595f4f434355504945440000000000000000000000604482015260640161074b565b61346e87858151811061344357634e487b7160e01b600052603260045260246000fd5b602002602001015184600960008c8152602001908152602001600020613b989092919063ffffffff16565b506134bb87858151811061349257634e487b7160e01b600052603260045260246000fd5b6020026020010151600a6000868152602001908152602001600020613d6c90919063ffffffff16565b5082156136bb576001865111156135ea5783158061350a5750856134e0600186614f45565b815181106134fe57634e487b7160e01b600052603260045260246000fd5b60200260200101518314155b80156135b25750600c546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905230916001600160a01b031690636352211e9060240160206040518083038186803b15801561356e57600080fd5b505afa158015613582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135a69190614317565b6001600160a01b031614155b156135e557828585815181106135d857634e487b7160e01b600052603260045260246000fd5b6020026020010181815250505b6136bb565b600c546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905230916001600160a01b031690636352211e9060240160206040518083038186803b15801561364757600080fd5b505afa15801561365b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367f9190614317565b6001600160a01b0316146136bb57828585815181106136ae57634e487b7160e01b600052603260045260246000fd5b6020026020010181815250505b50505080806136c990614fc1565b915050613371565b508051156108c95760005b81518110156136f757806136ef81614fc1565b9150506136dc565b50600c546040516315ddc53560e01b81526001600160a01b03909116906315ddc5359061258a90889030908690600401614b1d565b60008061373b60606002614e55565b6137459084614dfb565b9050600061375560206002614e55565b61375f9085614dfb565b9050838061376c81614f9f565b915050600061377a86612226565b9050806001600160a01b0316876001600160a01b031614156137a1576137a187828861312b565b60006137b1858386866000613935565b50905060006137bf82612226565b9050806001600160a01b0316836001600160a01b0316146138225760405162461bcd60e51b815260206004820152600960248201527f4e4f545f4f574e45520000000000000000000000000000000000000000000000604482015260640161074b565b50979650505050505050565b6001600160a01b03821660009081526001602052604090205460ff16156138975760405162461bcd60e51b815260206004820152601760248201527f494e56414c49445f415050524f56414c5f4348414e4745000000000000000000604482015260640161074b565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b606061390f82613d78565b60405160200161391f9190614a42565b6040516020818303038152906040529050919050565b6000806001600160a01b03861661398e5760405162461bcd60e51b815260206004820152601a60248201527f43414e27545f53454e445f544f5f5a45524f5f41444452455353000000000000604482015260640161074b565b60008060008515613a1f57600754600193506139b1908b908a9060ff1686613f1b565b915063ffffffff19821660008181526004602052604090205490915015613a1a5760405162461bcd60e51b815260206004820152601a60248201527f53544f524147455f49445f52455553455f464f5242494444454e000000000000604482015260640161074b565b613a42565b600754879350613a36908b908a9060ff1686613f1b565b91505063ffffffff1981165b613a766001600160a01b038a167affff0000000000000000000000000000000000000000000000000060c886901b16614de3565b6000828152600460209081526040808320939093556001600160a01b038c16825260039052908120805491613aaa83614fc1565b909155505060405182906001600160a01b038b16906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a490999098509650505050505050565b8015613b425763ffffffff1984166000908152600460205260409020600160ff1b6001600160a01b03841673ffffffffffffffffffffffffffffffffffffffff19861617179055611eeb565b6001600160a01b038216613b5b6001600160ff1b614f45565b841673ffffffffffffffffffffffffffffffffffffffff1916176004600063ffffffff198716815260208101919091526040016000205550505050565b6000613ba5848484613fa1565b949350505050565b60008080806132438686613fbe565b6000611f758383613ff7565b600080846001600160a01b0316634b808c46888887876040518563ffffffff1660e01b8152600401613bfd9493929190614ad4565b602060405180830381600087803b158015613c1757600080fd5b505af1158015613c2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4f91906148d3565b6001600160e01b0319167f4b808c46000000000000000000000000000000000000000000000000000000001491505095945050505050565b81546000908210613d005760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e60448201527f6473000000000000000000000000000000000000000000000000000000000000606482015260840161074b565b826000018281548110613d2357634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905092915050565b60006106a682612b5f565b60008080613d4f8585612b69565b600081815260029690960160205260409095205494959350505050565b6000611f758383614014565b60408051603480825260608281019093528391600090826020820181803683370190505090507f6162636465666768696a6b6c6d6e6f707172737475767778797a3233343536376002613dcc600886614ffa565b901b60ff1660208110613def57634e487b7160e01b600052603260045260246000fd5b1a60f81b81613dfd84614f88565b93508381518110613e1e57634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350613e58600884614dfb565b92505b8115613ba5577f6162636465666768696a6b6c6d6e6f707172737475767778797a323334353637613e8d602085614ffa565b60208110613eab57634e487b7160e01b600052603260045260246000fd5b1a60f81b81613eb984614f88565b93508381518110613eda57634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350613f14602084614dfb565b9250613e5b565b600061ffff8216613f2e60106002614e55565b613f3b9060ff8616614f26565b613f4760206002614e55565b613f5b9067ffffffffffffffff8816614f26565b613f6760606002614e55565b613f7a906001600160a01b038a16614f26565b613f849190614de3565b613f8e9190614de3565b613f989190614de3565b95945050505050565b60008281526002840160205260408120829055613ba58484613d6c565b6000818152600283016020526040812054819080613fec57613fe08585614063565b6000925092505061324b565b60019250905061324b565b60008181526002830160205260408120819055611f75838361406f565b600081815260018301602052604081205461405b575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556117a2565b5060006117a2565b6000611f75838361407b565b6000611f758383614093565b60008181526001830160205260408120541515611f75565b600081815260018301602052604081205480156141a65760006140b7600183614f45565b85549091506000906140cb90600190614f45565b905060008660000182815481106140f257634e487b7160e01b600052603260045260246000fd5b906000526020600020015490508087600001848154811061412357634e487b7160e01b600052603260045260246000fd5b60009182526020909120015561413a836001614de3565b6000828152600189016020526040902055865487908061416a57634e487b7160e01b600052603160045260246000fd5b600190038181906000526020600020016000905590558660010160008781526020019081526020016000206000905560019450505050506117a2565b60009150506117a2565b50805460008255906000526020600020908101906141ce91906141d1565b50565b5b808211156141e657600081556001016141d2565b5090565b600082601f8301126141fa578081fd5b8135602061420f61420a83614d77565b614d46565b82815281810190858301855b8581101561424457614232898684358b0101614251565b8452928401929084019060010161421b565b5090979650505050505050565b600082601f830112614261578081fd5b8135602061427161420a83614d77565b828152818101908583018385028701840188101561428d578586fd5b855b858110156142445781358452928401929084019060010161428f565b803580151581146106a957600080fd5b60008083601f8401126142cc578182fd5b50813567ffffffffffffffff8111156142e3578182fd5b60208301915083602082850101111561324b57600080fd5b60006020828403121561430c578081fd5b8135611f7581615050565b600060208284031215614328578081fd5b8151611f7581615050565b60008060408385031215614345578081fd5b823561435081615050565b9150602083013561436081615050565b809150509250929050565b60008060008060008060808789031215614383578182fd5b863561438e81615050565b9550602087013561439e81615050565b9450604087013567ffffffffffffffff808211156143ba578384fd5b818901915089601f8301126143cd578384fd5b8135818111156143db578485fd5b8a602080830285010111156143ee578485fd5b60208301965080955050606089013591508082111561440b578384fd5b5061441889828a016142bb565b979a9699509497509295939492505050565b60008060006060848603121561443e578283fd5b833561444981615050565b9250602084013561445981615050565b9150614467604085016142ab565b90509250925092565b600080600080600060a08688031215614487578283fd5b853561449281615050565b945060208601356144a281615050565b935060408601356144b281615050565b925060608601356144c281615050565b9150608086013560ff811681146144d7578182fd5b809150509295509295909350565b6000806000606084860312156144f9578081fd5b833561450481615050565b9250602084013561451481615050565b9150604084013567ffffffffffffffff81111561452f578182fd5b840160608187031215614540578182fd5b809150509250925092565b60008060006060848603121561455f578081fd5b833561456a81615050565b9250602084013561457a81615050565b929592945050506040919091013590565b6000806000806000608086880312156145a2578283fd5b85356145ad81615050565b945060208601356145bd81615050565b935060408601359250606086013567ffffffffffffffff8111156145df578182fd5b6145eb888289016142bb565b969995985093965092949392505050565b60008060008060808587031215614611578182fd5b843561461c81615050565b935060208581013561462d81615050565b935060408601359250606086013567ffffffffffffffff80821115614650578384fd5b818801915088601f830112614663578384fd5b8135818111156146755761467561503a565b61468784601f19601f84011601614d46565b9150808252898482850101111561469c578485fd5b8084840185840137810190920192909252939692955090935050565b600080600080608085870312156146cd578182fd5b84356146d881615050565b935060208501356146e881615050565b925060408501359150606085013567ffffffffffffffff81111561470a578182fd5b85016040818803121561471b578182fd5b939692955090935050565b6000806000806080858703121561473b578182fd5b843561474681615050565b9350602085013561475681615050565b925060408501359150606085013567ffffffffffffffff80821115614779578283fd5b9086019060c0828903121561478c578283fd5b61479660c0614d46565b8235828111156147a4578485fd5b6147b08a8286016141ea565b8252506020830135828111156147c4578485fd5b6147d08a8286016141ea565b6020830152506040830135828111156147e7578485fd5b6147f38a828601614251565b60408301525060608301358281111561480a578485fd5b6148168a828601614251565b60608301525060808301358281111561482d578485fd5b6148398a828601614251565b60808301525060a083013560a082015280935050505092959194509250565b6000806040838503121561486a578182fd5b823561487581615050565b9150614883602084016142ab565b90509250929050565b6000806040838503121561489e578182fd5b82356148a981615050565b946020939093013593505050565b6000602082840312156148c8578081fd5b8135611f7581615065565b6000602082840312156148e4578081fd5b8151611f7581615065565b600060208284031215614900578081fd5b5035919050565b60008060408385031215614919578182fd5b82359150602083013567ffffffffffffffff811115614936578182fd5b61494285828601614251565b9150509250929050565b6000815180845260208085019450848183028601828601855b8581101561424457838303895261497d8383516149dc565b98850198925090840190600101614965565b60008284527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156149c0578081fd5b6020830280836020870137939093016020019283525090919050565b6000815180845260208085019450808401835b83811015614a0b578151875295820195908201906001016149ef565b509495945050505050565b60008151808452614a2e816020860160208601614f5c565b601f01601f19169290920160200192915050565b60007f697066733a2f2f6261667962656900000000000000000000000000000000000082528251614a7a81600e850160208701614f5c565b7f2f00000000000000000000000000000000000000000000000000000000000000600e9390910192830152507f6573746174652e6a736f6e000000000000000000000000000000000000000000600f820152601a01919050565b60006001600160a01b03808716835280861660208401525060806040830152614b0060808301856149dc565b8281036060840152614b128185614a16565b979650505050505050565b60006001600160a01b03808616835280851660208401525060806040830152614b4960808301846149dc565b82810360609093019290925281526020019392505050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152612f0f6080830184614a16565b600060208252611f7560208301846149dc565b600060208252611f756020830184614a16565b600060208252614bc98384614d9b565b60606020850152614bde60808501828461498f565b915050614bee6020850185614d9b565b601f19858403016040860152614c0583828461498f565b92505050604084013560608401528091505092915050565b600060208252825160406020840152614c3960608401826149dc565b90506020840151601f19848303016040850152613f9882826149dc565b600060208252825160c06020840152614c7260e084018261494c565b90506020840151601f1980858403016040860152614c90838361494c565b92506040860151915080858403016060860152614cad83836149dc565b92506060860151915080858403016080860152614cca83836149dc565b925060808601519150808584030160a086015250614ce882826149dc565b91505060a084015160c08401528091505092915050565b6000808335601e19843603018112614d15578283fd5b83018035915067ffffffffffffffff821115614d2f578283fd5b602090810192508102360382131561324b57600080fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614d6f57614d6f61503a565b604052919050565b600067ffffffffffffffff821115614d9157614d9161503a565b5060209081020190565b6000808335601e19843603018112614db1578283fd5b830160208101925035905067ffffffffffffffff811115614dd157600080fd5b60208102360383131561324b57600080fd5b60008219821115614df657614df661500e565b500190565b600082614e0a57614e0a615024565b500490565b80825b6001808611614e215750614e4c565b818704821115614e3357614e3361500e565b80861615614e4057918102915b9490941c938002614e12565b94509492505050565b6000611f7560001960ff851684600082614e7157506001611f75565b81614e7e57506000611f75565b8160018114614e945760028114614e9e57614ecb565b6001915050611f75565b60ff841115614eaf57614eaf61500e565b6001841b915084821115614ec557614ec561500e565b50611f75565b5060208310610133831016604e8410600b8410161715614efe575081810a83811115614ef957614ef961500e565b611f75565b614f0b8484846001614e0f565b808604821115614f1d57614f1d61500e565b02949350505050565b6000816000190483118215151615614f4057614f4061500e565b500290565b600082821015614f5757614f5761500e565b500390565b60005b83811015614f77578181015183820152602001614f5f565b83811115611eeb5750506000910152565b600081614f9757614f9761500e565b506000190190565b600061ffff80831681811415614fb757614fb761500e565b6001019392505050565b6000600019821415614fd557614fd561500e565b5060010190565b600067ffffffffffffffff80831681811415614fb757614fb761500e565b60008261500957615009615024565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146141ce57600080fd5b6001600160e01b0319811681146141ce57600080fdfea26469706673582212207d5730ac740cb3b35e9f646824a237e6dd5cef6503ad0ce906f1cf08f615ce6864736f6c63430008020033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102925760003560e01c8063654b748a11610160578063a22cb465116100d8578063db44fe071161008c578063eeb5a5d111610071578063eeb5a5d114610604578063f366751714610617578063f56baa0e1461063057610292565b8063db44fe07146105c1578063e985e9c5146105f157610292565b8063b88d4fde116100bd578063b88d4fde1461058a578063c87b56dd1461059d578063ce1b815f146105b057610292565b8063a22cb46514610564578063ac9fe4211461057757610292565b80638f2839701161012f57806395d89b411161011457806395d89b41146105055780639d7a3b871461053e5780639df4c3bf1461055157610292565b80638f283970146104d25780639381da6e146104e557610292565b8063654b748a1461046f5780636e9960c31461049b57806370a08231146104ac57806379cc6790146104bf57610292565b806323b872dd1161020e57806342842e0e116101c25780634b808c46116101a75780634b808c461461042c578063572b6c051461043a5780636352211e1461045c57610292565b806342842e0e1461040657806342966c681461041957610292565b80632b991746116101f35780632b991746146103cd5780632c4d4d18146103e057806333b47e58146103f357610292565b806323b872dd146103a757806328cfbd46146103ba57610292565b80630a148eb31161026557806315ddc5351161024a57806315ddc5351461035357806321ab0c711461036657806322e695391461038757610292565b80630a148eb314610314578063150b7a021461032757610292565b806301ffc9a71461029757806306fdde03146102bf578063081812fc146102d4578063095ea7b3146102ff575b600080fd5b6102aa6102a53660046148b7565b610643565b60405190151581526020015b60405180910390f35b6102c76106ae565b6040516102b69190614ba6565b6102e76102e23660046148ef565b6106e6565b6040516001600160a01b0390911681526020016102b6565b61031261030d36600461488c565b610785565b005b6103126103223660046146b8565b6108d0565b61033a61033536600461458b565b610b10565b6040516001600160e01b031990911681526020016102b6565b61031261036136600461436b565b610b81565b6103796103743660046148ef565b610bf3565b6040519081526020016102b6565b61039a6103953660046148ef565b610c02565b6040516102b69190614b93565b6103126103b536600461454b565b610cec565b6103126103c836600461436b565b610dba565b6103126103db36600461454b565b610e2f565b6103126103ee3660046142fb565b610fc7565b610312610401366004614470565b6110b0565b61031261041436600461454b565b611208565b6103126104273660046148ef565b611223565b61033a61033536600461436b565b6102aa6104483660046142fb565b6002546001600160a01b0390811691161490565b6102e761046a3660046148ef565b611250565b6102aa61047d3660046142fb565b6001600160a01b031660009081526001602052604090205460ff1690565b6000546001600160a01b03166102e7565b6103796104ba3660046142fb565b6112b3565b6103126104cd36600461488c565b611327565b6103126104e03660046142fb565b6114db565b6104f86104f33660046148ef565b6115ab565b6040516102b69190614c1d565b60408051808201909152600681527f455354415445000000000000000000000000000000000000000000000000000060208201526102c7565b6102aa61054c366004614907565b611743565b61037961055f366004614726565b6117a8565b610312610572366004614858565b611d6f565b610312610585366004614858565b611d81565b6103126105983660046145fc565b611e64565b6102c76105ab3660046148ef565b611ef1565b6002546001600160a01b03166102e7565b6102aa6105cf3660046148ef565b63ffffffff1916600090815260046020526040902054600160a01b9081161490565b6102aa6105ff366004614333565b611f7c565b61031261061236600461442a565b611fce565b6102e7600754630100000090046001600160a01b031690565b61037961063e3660046144e5565b6120bf565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614806106a657507f80ac58cd000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b90505b919050565b60408051808201909152601981527f5468652053616e64626f783a2045535441544520746f6b656e0000000000000060208201525b90565b60008060006106f4846121e1565b90925090506001600160a01b0382166107545760405162461bcd60e51b815260206004820152601160248201527f4e4f4e4558495354454e545f544f4b454e00000000000000000000000000000060448201526064015b60405180910390fd5b801561077a575050506000818152600660205260409020546001600160a01b03166106a9565b6000925050506106a9565b63ffffffff198116600090815260046020526040812054906107a683612226565b905060006107b261227f565b90506001600160a01b03821661080a5760405162461bcd60e51b815260206004820152601160248201527f4e4f4e4558495354454e545f544f4b454e000000000000000000000000000000604482015260640161074b565b806001600160a01b0316826001600160a01b0316148061084257506001600160a01b03811660009081526001602052604090205460ff165b8061087257506001600160a01b0380831660009081526005602090815260408083209385168352929052205460ff165b6108be5760405162461bcd60e51b815260206004820152601560248201527f554e415554484f52495a45445f415050524f56414c0000000000000000000000604482015260640161074b565b6108c98386866122c9565b5050505050565b63ffffffff198216600090815260046020526040902054600160a01b9081161461093c5760405162461bcd60e51b815260206004820152601060248201527f41535345545f4e4f545f4255524e454400000000000000000000000000000000604482015260640161074b565b6001600160a01b0384163014156109955760405162461bcd60e51b815260206004820152600d60248201527f4e4f545f46524f4d5f5448495300000000000000000000000000000000000000604482015260640161074b565b63ffffffff19821660006109a761227f565b9050856001600160a01b0316816001600160a01b031614806109e157506001600160a01b03811660009081526001602052604090205460ff165b610a2d5760405162461bcd60e51b815260206004820152600e60248201527f4e4f545f415554484f52495a4544000000000000000000000000000000000000604482015260640161074b565b610a37868561237f565b610abf8585610a496020870187614cff565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610a88925050506020880188614cff565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061244c92505050565b610b088286610ace8680614cff565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250600192506125c3915050565b505050505050565b60405162461bcd60e51b815260206004820152603260248201527f706c656173652063616c6c20637265617465457374617465206f72207570646160448201527f74654573746174652066756e6374696f6e730000000000000000000000000000606482015260009060840161074b565b610b08868686868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020601f8a0181900481028201810190925288815292508891508790819084018382808284376000920182905250925061275b915050565b600063ffffffff1982166106a6565b6000818152600a6020526040812060609190610c1d90612b5f565b67ffffffffffffffff811115610c4357634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610c6c578160200160208202803683370190505b50905060005b6000848152600a60205260409020610c8990612b5f565b811015610ce5576000848152600a60205260409020610ca89082612b69565b828281518110610cc857634e487b7160e01b600052603260045260246000fd5b602090810291909101015280610cdd81614fc1565b915050610c72565b5092915050565b610cf7838383612b75565b50610d03838383612d8d565b6001600160a01b0382163b15158015610d415750610d41827f5e8bf64400000000000000000000000000000000000000000000000000000000612e52565b15610db557610d69610d5161227f565b84848460405180602001604052806000815250612f19565b610db55760405162461bcd60e51b815260206004820152601860248201527f4552433732315f5452414e534645525f52454a45435445440000000000000000604482015260640161074b565b505050565b610b08868686868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020601f8a0181900481028201810190925288815292508891508790819084018382808284376000920191909152506001925061275b915050565b63ffffffff19811660009081526004602052604081205490610e4f61227f565b90506001600160a01b038516610ea75760405162461bcd60e51b815260206004820152601360248201527f5a45524f5f414444524553535f53454e44455200000000000000000000000000604482015260640161074b565b846001600160a01b0316816001600160a01b03161480610edf57506001600160a01b03811660009081526001602052604090205460ff165b80610f0f57506001600160a01b0380861660009081526005602090815260408083209385168352929052205460ff165b610f5b5760405162461bcd60e51b815260206004820152601560248201527f554e415554484f52495a45445f415050524f56414c0000000000000000000000604482015260640161074b565b846001600160a01b0316826001600160a01b031614610fbc5760405162461bcd60e51b815260206004820152601060248201527f4f574e45525f4e4f545f53454e44455200000000000000000000000000000000604482015260640161074b565b6108c98285856122c9565b6000546001600160a01b031633146110215760405162461bcd60e51b815260206004820152600a60248201527f41444d494e5f4f4e4c5900000000000000000000000000000000000000000000604482015260640161074b565b600754604080516001600160a01b0363010000009093048316815291831660208301527f3b0007eb941cf645526cbb3a4fdaecda9d28ce4843167d9263b536a1f1edc0f6910160405180910390a1600780546001600160a01b039092166301000000027fffffffffffffffffff0000000000000000000000000000000000000000ffffff909216919091179055565b60075462010000900460ff166110d157600754610100900460ff16156110d5565b303b155b6111475760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161074b565b60075462010000900460ff1615801561119457600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff62ff0000199091166201000017166101001790555b6000805473ffffffffffffffffffffffffffffffffffffffff199081166001600160a01b0388811691909117909255600c80548216868416179055600b80549091169186169190911790556007805460ff191660ff84161790558015610b08576007805462ff000019169055505050505050565b610db583838360405180602001604052806000815250611e64565b600061122d61227f565b90506112398183612fd8565b61124c8161124684612226565b8461312b565b5050565b600061125b82612226565b90506001600160a01b0381166106a95760405162461bcd60e51b815260206004820152601160248201527f4e4f4e4558495354414e545f544f4b454e000000000000000000000000000000604482015260640161074b565b60006001600160a01b03821661130b5760405162461bcd60e51b815260206004820152601260248201527f5a45524f5f414444524553535f4f574e45520000000000000000000000000000604482015260640161074b565b506001600160a01b031660009081526003602052604090205490565b6001600160a01b03821661137d5760405162461bcd60e51b815260206004820152601560248201527f4e4f545f46524f4d5f5a45524f5f414444524553530000000000000000000000604482015260640161074b565b600080611389836121e1565b90925090506001600160a01b0382166113e45760405162461bcd60e51b815260206004820152601160248201527f4e4f4e4558495354454e545f544f4b454e000000000000000000000000000000604482015260640161074b565b60006113ee61227f565b9050846001600160a01b0316816001600160a01b03161480611431575081801561143157506000848152600660205260409020546001600160a01b038281169116145b8061145457506001600160a01b03811660009081526001602052604090205460ff165b8061148457506001600160a01b0380861660009081526005602090815260408083209385168352929052205460ff165b6114d05760405162461bcd60e51b815260206004820152601160248201527f554e415554484f52495a45445f4255524e000000000000000000000000000000604482015260640161074b565b6108c985848661312b565b6000546001600160a01b031633146115355760405162461bcd60e51b815260206004820152601360248201527f41444d494e5f4143434553535f44454e49454400000000000000000000000000604482015260640161074b565b600054604080516001600160a01b03928316815291831660208301527f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f910160405180910390a16000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6040805180820190915260608082526020820152600063ffffffff1983166000818152600960205260408120919250906115e490613229565b905060008167ffffffffffffffff81111561160f57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611638578160200160208202803683370190505b50905060008267ffffffffffffffff81111561166457634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561168d578160200160208202803683370190505b50905060005b8381101561172857600085815260096020526040812081906116b59084613234565b91509150818584815181106116da57634e487b7160e01b600052603260045260246000fd5b6020026020010181815250508084848151811061170757634e487b7160e01b600052603260045260246000fd5b6020026020010181815250505050808061172090614fc1565b915050611693565b50604080518082019091529182526020820152949350505050565b805160009081805b8281101561179d578585828151811061177457634e487b7160e01b600052603260045260246000fd5b6020026020010151141561178b576001915061179d565b8061179581614fc1565b91505061174b565b509150505b92915050565b60006117b48584612fd8565b60a082015163ffffffff1984166000818152600860205260408120929092558351805191929160019081106117f957634e487b7160e01b600052603260045260246000fd5b60200260200101515190506000846020015160018151811061182b57634e487b7160e01b600052603260045260246000fd5b60200260200101515190506000856040015151905061184f848a8860600151613252565b8115611c1a57856020015160008151811061187a57634e487b7160e01b600052603260045260246000fd5b60200260200101515182146118d15760405162461bcd60e51b815260206004820152601c60248201527f444946464552454e545f4c454e4754485f4c414e44535f47414d455300000000604482015260640161074b565b82866040015151111561194c5760405162461bcd60e51b815260206004820152602e60248201527f47414d45535f544f5f52455553455f4d5553545f42455f50524553454e545f4960448201527f4e5f47414d45535f544f5f414444000000000000000000000000000000000000606482015260840161074b565b81866040015151106119c65760405162461bcd60e51b815260206004820152603160248201527f47414d45535f544f5f52455553455f4d5553545f42455f50524553454e545f4960448201527f4e5f47414d45535f544f5f52454d4f5645000000000000000000000000000000606482015260840161074b565b60005b81811015611ad4578651805160019081106119f457634e487b7160e01b600052603260045260246000fd5b60200260200101518181518110611a1b57634e487b7160e01b600052603260045260246000fd5b602002602001015187604001518281518110611a4757634e487b7160e01b600052603260045260246000fd5b602002602001015114611ac25760405162461bcd60e51b815260206004820152602e60248201527f47414d45535f544f5f52455553455f4d5553545f42455f50524553454e545f4960448201527f4e5f47414d45535f544f5f414444000000000000000000000000000000000000606482015260840161074b565b80611acc81614fc1565b9150506119c9565b506000611ae18284614f45565b905060008167ffffffffffffffff811115611b0c57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611b35578160200160208202803683370190505b509050825b84811015611bde578860200151600181518110611b6757634e487b7160e01b600052603260045260246000fd5b60200260200101518181518110611b8e57634e487b7160e01b600052603260045260246000fd5b6020026020010151828583611ba39190614f45565b81518110611bc157634e487b7160e01b600052603260045260246000fd5b602090810291909101015280611bd681614fc1565b915050611b3a565b50611c178b878a60200151600181518110611c0957634e487b7160e01b600052603260045260246000fd5b60200260200101518461244c565b50505b8215611cfc5785518051600090611c4157634e487b7160e01b600052603260045260246000fd5b6020026020010151518314611c985760405162461bcd60e51b815260206004820152601c60248201527f444946464552454e545f4c454e4754485f4c414e44535f47414d455300000000604482015260640161074b565b611cfc89858860000151600081518110611cc257634e487b7160e01b600052603260045260246000fd5b60200260200101518960000151600181518110611cef57634e487b7160e01b600052603260045260246000fd5b6020026020010151613318565b611d0d848a886080015160006125c3565b6000611d19898961372c565b90506000611d26866115ab565b905081897f9e7c7d8ddece27ce406d7f0d11566fca4d42b7f4a641c0ef4efa85e359c6e4a58a604051611d599190614c56565b60405180910390a3505050505050949350505050565b61124c611d7a61227f565b838361382e565b6000546001600160a01b03163314611e015760405162461bcd60e51b815260206004820152602c60248201527f6f6e6c792061646d696e20697320616c6c6f77656420746f206164642073757060448201527f6572206f70657261746f72730000000000000000000000000000000000000000606482015260840161074b565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527f44f92d27abdf4cfb6a7d712c3af68f3be086d4ca747ab802c36f67d6790060d8910160405180910390a15050565b611e6f848484612b75565b50611e7b848484612d8d565b6001600160a01b0383163b15611eeb57611e9f611e9661227f565b85858585612f19565b611eeb5760405162461bcd60e51b815260206004820152601860248201527f4552433732315f5452414e534645525f52454a45435445440000000000000000604482015260640161074b565b50505050565b60606000611efe83612226565b6001600160a01b03161415611f555760405162461bcd60e51b815260206004820152601660248201527f4255524e45445f4f525f4e455645525f4d494e54454400000000000000000000604482015260640161074b565b63ffffffff198216600081815260086020526040902054611f7590613904565b9392505050565b6001600160a01b03808316600090815260056020908152604080832093851683529290529081205460ff1680611f755750506001600160a01b031660009081526001602052604090205460ff16919050565b6001600160a01b0383166120245760405162461bcd60e51b815260206004820152601660248201527f496e76616c69642073656e646572206164647265737300000000000000000000604482015260640161074b565b600061202e61227f565b9050836001600160a01b0316816001600160a01b0316148061206857506001600160a01b03811660009081526001602052604090205460ff165b6120b45760405162461bcd60e51b815260206004820152601c60248201527f554e415554484f52495a45445f415050524f56455f464f525f414c4c00000000604482015260640161074b565b611eeb84848461382e565b60006120ce6020830183614cff565b90506120da8380614cff565b9050146121295760405162461bcd60e51b815260206004820152601c60248201527f444946464552454e545f4c454e4754485f4c414e44535f47414d455300000000604482015260640161074b565b60008061218586866007601781819054906101000a900467ffffffffffffffff168092919061215790614fdc565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550600180613935565b6000818152600860205260408082208189013590555192945090925083917f0e1331b3d93257377695e09c5f57e70594445e5b47ebdd513b8db11f7ce9ed7b906121d0908890614bb9565b60405180910390a350949350505050565b63ffffffff1981166000908152600460205260408120548190600160a01b80821614156122115760009250612215565b8092505b600160ff1b80821614915050915091565b63ffffffff1981166000908152600460205260408120548260c882901c63ffffffff16600160a01b808416148061226557508061ffff168261ffff1614155b1561227657600093505050506106a9565b50909392505050565b6002546000906001600160a01b03163314156122c257507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c6106e3565b50336106e3565b60006122d482612226565b90506001600160a01b0383166122f6576122f18285836000613af6565b612338565b6123038285836001613af6565b6000828152600660205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0385161790555b81836001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a450505050565b6001600160a01b0382166123d55760405162461bcd60e51b815260206004820152601360248201527f53454e4445525f5a45524f5f4144445245535300000000000000000000000000604482015260640161074b565b63ffffffff1981166000908152600460205260409020546001600160a01b0316826001600160a01b03161461124c5760405162461bcd60e51b815260206004820152601b60248201527f4c4153545f4f574e45525f4e4f545f455155414c5f53454e4445520000000000604482015260640161074b565b606060005b83518110156125555761248a84828151811061247d57634e487b7160e01b600052603260045260246000fd5b6020026020010151610c02565b9150600a60008583815181106124b057634e487b7160e01b600052603260045260246000fd5b602002602001015181526020019081526020016000206000808201600080820160006124dc91906141b0565b5050505060005b82518110156125425761252f83828151811061250f57634e487b7160e01b600052603260045260246000fd5b602090810291909101810151600089815260099092526040822091613b98565b508061253a81614fc1565b9150506124e3565b508061254d81614fc1565b915050612451565b50600c546040516315ddc53560e01b81526001600160a01b03909116906315ddc5359061258a90309089908790600401614b1d565b600060405180830381600087803b1580156125a457600080fd5b505af11580156125b8573d6000803e3d6000fd5b505050505050505050565b815160005b818110156127265760008061261f8684815181106125f657634e487b7160e01b600052603260045260246000fd5b6020026020010151600960008b8152602001908152602001600020613bad90919063ffffffff16565b91509150848061262d575080155b6126795760405162461bcd60e51b815260206004820152601760248201527f47414d455f5354494c4c5f484f4c44535f415f4c414e44000000000000000000604482015260640161074b565b6126c586848151811061269c57634e487b7160e01b600052603260045260246000fd5b6020026020010151600960008b8152602001908152602001600020613bbc90919063ffffffff16565b6127115760405162461bcd60e51b815260206004820152601360248201527f4c414e445f444f45535f4e4f545f455849535400000000000000000000000000604482015260640161074b565b5050808061271e90614fc1565b9150506125c8565b50600b546040516315ddc53560e01b81526001600160a01b03909116906315ddc5359061258a90309088908890600401614b1d565b600061276561227f565b90506000866001600160a01b0316826001600160a01b031614806127a157506001600160a01b03821660009081526001602052604090205460ff165b806127d157506001600160a01b0380881660009081526005602090815260408083209386168352929052205460ff165b90506001600160a01b0387166128295760405162461bcd60e51b815260206004820152601460248201527f4e4f545f46524f4d5f5a45524f41444452455353000000000000000000000000604482015260640161074b565b6001600160a01b03861661287f5760405162461bcd60e51b815260206004820152601260248201527f4e4f545f544f5f5a45524f414444524553530000000000000000000000000000604482015260640161074b565b845160005b8651811015612a3d5760008782815181106128af57634e487b7160e01b600052603260045260246000fd5b6020026020010151905080600014156128d557826128cc81614f88565b93505050612a2b565b6000806128e1836121e1565b915091508b6001600160a01b0316826001600160a01b0316146129465760405162461bcd60e51b815260206004820152601b60248201527f42415443485452414e5346455246524f4d5f4e4f545f4f574e45520000000000604482015260640161074b565b8580612973575080801561297357506000838152600660205260409020546001600160a01b038881169116145b6129bf5760405162461bcd60e51b815260206004820152600e60248201527f4e4f545f415554484f52495a4544000000000000000000000000000000000000604482015260640161074b565b6129e6836004600063ffffffff1983168152602001908152602001600020548d6000613af6565b828b6001600160a01b03168d6001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505b80612a3581614fc1565b915050612884565b50866001600160a01b0316886001600160a01b031614612ab2576001600160a01b03881660009081526003602052604081208054839290612a7f908490614f45565b90915550506001600160a01b03871660009081526003602052604081208054839290612aac908490614de3565b90915550505b6001600160a01b0387163b15158015612af757508380612af75750612af7877f5e8bf64400000000000000000000000000000000000000000000000000000000612e52565b15612b5557612b098389898989613bc8565b612b555760405162461bcd60e51b815260206004820152601e60248201527f4552433732315f42415443485f5452414e534645525f52454a45435445440000604482015260640161074b565b5050505050505050565b60006106a6825490565b6000611f758383613c87565b6000806000612b83846121e1565b915091506000612b9161227f565b90506001600160a01b038316612be95760405162461bcd60e51b815260206004820152601160248201527f4e4f4e4558495354454e545f544f4b454e000000000000000000000000000000604482015260640161074b565b866001600160a01b0316836001600160a01b031614612c4a5760405162461bcd60e51b815260206004820152601760248201527f434845434b5452414e534645525f4e4f545f4f574e4552000000000000000000604482015260640161074b565b6001600160a01b038616612ca05760405162461bcd60e51b815260206004820152601260248201527f4e4f545f544f5f5a45524f414444524553530000000000000000000000000000604482015260640161074b565b826001600160a01b0316816001600160a01b03161480612cd857506001600160a01b03811660009081526001602052604090205460ff165b80612d0857506001600160a01b0380881660009081526005602090815260408083209385168352929052205460ff165b80612d345750818015612d3457506000858152600660205260409020546001600160a01b038281169116145b612d805760405162461bcd60e51b815260206004820152601560248201527f554e415554484f52495a45445f5452414e534645520000000000000000000000604482015260640161074b565b5060019695505050505050565b6001600160a01b0383166000908152600360205260408120805491612db183614f88565b90915550506001600160a01b0382166000908152600360205260408120805491612dda83614fc1565b9190505550612e0c8160046000612df58563ffffffff191690565b815260200190815260200160002054846000613af6565b80826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b604080516001600160e01b031983166024808301919091528251808303909101815260449091018252602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a7000000000000000000000000000000000000000000000000000000001781528251935160008082529485948594909392908183858c612710fa955080519450505050609e5a11612f0557634e487b7160e01b600052600160045260246000fd5b828015612f0f5750815b9695505050505050565b600080846001600160a01b031663150b7a02888887876040518563ffffffff1660e01b8152600401612f4e9493929190614b61565b602060405180830381600087803b158015612f6857600080fd5b505af1158015612f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa091906148d3565b6001600160e01b0319167f150b7a02000000000000000000000000000000000000000000000000000000001491505095945050505050565b600080612fe4836121e1565b90925090506001600160a01b03821661303f5760405162461bcd60e51b815260206004820152601460248201527f544f4b454e5f444f45535f4e4f545f4558495354000000000000000000000000604482015260640161074b565b600061304961227f565b9050846001600160a01b0316836001600160a01b0316148061308357506001600160a01b03811660009081526001602052604090205460ff165b806130b357506001600160a01b0380861660009081526005602090815260408083209385168352929052205460ff165b806130df57508180156130df57506000848152600660205260409020546001600160a01b038281169116145b6108c95760405162461bcd60e51b815260206004820152600c60248201527f4e4f545f415050524f5645440000000000000000000000000000000000000000604482015260640161074b565b816001600160a01b0316836001600160a01b03161461318c5760405162461bcd60e51b815260206004820152600960248201527f4e4f545f4f574e45520000000000000000000000000000000000000000000000604482015260640161074b565b63ffffffff198116600160a01b6131a86001600160ff1b614f45565b6000838152600460209081526040808320805494909416949094179092556001600160a01b038716815260039091529081208054916131e683614f88565b909155505060405182906000906001600160a01b038716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a450505050565b60006106a682613d36565b60008080806132438686613d41565b909450925050505b9250929050565b805160005b818110156132b5576132a283828151811061328257634e487b7160e01b600052603260045260246000fd5b602090810291909101810151600088815260099092526040822091613b98565b50806132ad81614fc1565b915050613257565b50600b546040516315ddc53560e01b81526001600160a01b03909116906315ddc535906132ea90869030908790600401614b1d565b600060405180830381600087803b15801561330457600080fd5b505af1158015612b55573d6000803e3d6000fd5b6000815167ffffffffffffffff81111561334257634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561336b578160200160208202803683370190505b50905060005b83518110156136d157600083828151811061339c57634e487b7160e01b600052603260045260246000fd5b602002602001015190506000806133cc8785815181106125f657634e487b7160e01b600052603260045260246000fd5b91509150806000146134205760405162461bcd60e51b815260206004820152601560248201527f4c414e445f414c52454144595f4f434355504945440000000000000000000000604482015260640161074b565b61346e87858151811061344357634e487b7160e01b600052603260045260246000fd5b602002602001015184600960008c8152602001908152602001600020613b989092919063ffffffff16565b506134bb87858151811061349257634e487b7160e01b600052603260045260246000fd5b6020026020010151600a6000868152602001908152602001600020613d6c90919063ffffffff16565b5082156136bb576001865111156135ea5783158061350a5750856134e0600186614f45565b815181106134fe57634e487b7160e01b600052603260045260246000fd5b60200260200101518314155b80156135b25750600c546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905230916001600160a01b031690636352211e9060240160206040518083038186803b15801561356e57600080fd5b505afa158015613582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135a69190614317565b6001600160a01b031614155b156135e557828585815181106135d857634e487b7160e01b600052603260045260246000fd5b6020026020010181815250505b6136bb565b600c546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905230916001600160a01b031690636352211e9060240160206040518083038186803b15801561364757600080fd5b505afa15801561365b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367f9190614317565b6001600160a01b0316146136bb57828585815181106136ae57634e487b7160e01b600052603260045260246000fd5b6020026020010181815250505b50505080806136c990614fc1565b915050613371565b508051156108c95760005b81518110156136f757806136ef81614fc1565b9150506136dc565b50600c546040516315ddc53560e01b81526001600160a01b03909116906315ddc5359061258a90889030908690600401614b1d565b60008061373b60606002614e55565b6137459084614dfb565b9050600061375560206002614e55565b61375f9085614dfb565b9050838061376c81614f9f565b915050600061377a86612226565b9050806001600160a01b0316876001600160a01b031614156137a1576137a187828861312b565b60006137b1858386866000613935565b50905060006137bf82612226565b9050806001600160a01b0316836001600160a01b0316146138225760405162461bcd60e51b815260206004820152600960248201527f4e4f545f4f574e45520000000000000000000000000000000000000000000000604482015260640161074b565b50979650505050505050565b6001600160a01b03821660009081526001602052604090205460ff16156138975760405162461bcd60e51b815260206004820152601760248201527f494e56414c49445f415050524f56414c5f4348414e4745000000000000000000604482015260640161074b565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b606061390f82613d78565b60405160200161391f9190614a42565b6040516020818303038152906040529050919050565b6000806001600160a01b03861661398e5760405162461bcd60e51b815260206004820152601a60248201527f43414e27545f53454e445f544f5f5a45524f5f41444452455353000000000000604482015260640161074b565b60008060008515613a1f57600754600193506139b1908b908a9060ff1686613f1b565b915063ffffffff19821660008181526004602052604090205490915015613a1a5760405162461bcd60e51b815260206004820152601a60248201527f53544f524147455f49445f52455553455f464f5242494444454e000000000000604482015260640161074b565b613a42565b600754879350613a36908b908a9060ff1686613f1b565b91505063ffffffff1981165b613a766001600160a01b038a167affff0000000000000000000000000000000000000000000000000060c886901b16614de3565b6000828152600460209081526040808320939093556001600160a01b038c16825260039052908120805491613aaa83614fc1565b909155505060405182906001600160a01b038b16906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a490999098509650505050505050565b8015613b425763ffffffff1984166000908152600460205260409020600160ff1b6001600160a01b03841673ffffffffffffffffffffffffffffffffffffffff19861617179055611eeb565b6001600160a01b038216613b5b6001600160ff1b614f45565b841673ffffffffffffffffffffffffffffffffffffffff1916176004600063ffffffff198716815260208101919091526040016000205550505050565b6000613ba5848484613fa1565b949350505050565b60008080806132438686613fbe565b6000611f758383613ff7565b600080846001600160a01b0316634b808c46888887876040518563ffffffff1660e01b8152600401613bfd9493929190614ad4565b602060405180830381600087803b158015613c1757600080fd5b505af1158015613c2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4f91906148d3565b6001600160e01b0319167f4b808c46000000000000000000000000000000000000000000000000000000001491505095945050505050565b81546000908210613d005760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e60448201527f6473000000000000000000000000000000000000000000000000000000000000606482015260840161074b565b826000018281548110613d2357634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905092915050565b60006106a682612b5f565b60008080613d4f8585612b69565b600081815260029690960160205260409095205494959350505050565b6000611f758383614014565b60408051603480825260608281019093528391600090826020820181803683370190505090507f6162636465666768696a6b6c6d6e6f707172737475767778797a3233343536376002613dcc600886614ffa565b901b60ff1660208110613def57634e487b7160e01b600052603260045260246000fd5b1a60f81b81613dfd84614f88565b93508381518110613e1e57634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350613e58600884614dfb565b92505b8115613ba5577f6162636465666768696a6b6c6d6e6f707172737475767778797a323334353637613e8d602085614ffa565b60208110613eab57634e487b7160e01b600052603260045260246000fd5b1a60f81b81613eb984614f88565b93508381518110613eda57634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350613f14602084614dfb565b9250613e5b565b600061ffff8216613f2e60106002614e55565b613f3b9060ff8616614f26565b613f4760206002614e55565b613f5b9067ffffffffffffffff8816614f26565b613f6760606002614e55565b613f7a906001600160a01b038a16614f26565b613f849190614de3565b613f8e9190614de3565b613f989190614de3565b95945050505050565b60008281526002840160205260408120829055613ba58484613d6c565b6000818152600283016020526040812054819080613fec57613fe08585614063565b6000925092505061324b565b60019250905061324b565b60008181526002830160205260408120819055611f75838361406f565b600081815260018301602052604081205461405b575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556117a2565b5060006117a2565b6000611f75838361407b565b6000611f758383614093565b60008181526001830160205260408120541515611f75565b600081815260018301602052604081205480156141a65760006140b7600183614f45565b85549091506000906140cb90600190614f45565b905060008660000182815481106140f257634e487b7160e01b600052603260045260246000fd5b906000526020600020015490508087600001848154811061412357634e487b7160e01b600052603260045260246000fd5b60009182526020909120015561413a836001614de3565b6000828152600189016020526040902055865487908061416a57634e487b7160e01b600052603160045260246000fd5b600190038181906000526020600020016000905590558660010160008781526020019081526020016000206000905560019450505050506117a2565b60009150506117a2565b50805460008255906000526020600020908101906141ce91906141d1565b50565b5b808211156141e657600081556001016141d2565b5090565b600082601f8301126141fa578081fd5b8135602061420f61420a83614d77565b614d46565b82815281810190858301855b8581101561424457614232898684358b0101614251565b8452928401929084019060010161421b565b5090979650505050505050565b600082601f830112614261578081fd5b8135602061427161420a83614d77565b828152818101908583018385028701840188101561428d578586fd5b855b858110156142445781358452928401929084019060010161428f565b803580151581146106a957600080fd5b60008083601f8401126142cc578182fd5b50813567ffffffffffffffff8111156142e3578182fd5b60208301915083602082850101111561324b57600080fd5b60006020828403121561430c578081fd5b8135611f7581615050565b600060208284031215614328578081fd5b8151611f7581615050565b60008060408385031215614345578081fd5b823561435081615050565b9150602083013561436081615050565b809150509250929050565b60008060008060008060808789031215614383578182fd5b863561438e81615050565b9550602087013561439e81615050565b9450604087013567ffffffffffffffff808211156143ba578384fd5b818901915089601f8301126143cd578384fd5b8135818111156143db578485fd5b8a602080830285010111156143ee578485fd5b60208301965080955050606089013591508082111561440b578384fd5b5061441889828a016142bb565b979a9699509497509295939492505050565b60008060006060848603121561443e578283fd5b833561444981615050565b9250602084013561445981615050565b9150614467604085016142ab565b90509250925092565b600080600080600060a08688031215614487578283fd5b853561449281615050565b945060208601356144a281615050565b935060408601356144b281615050565b925060608601356144c281615050565b9150608086013560ff811681146144d7578182fd5b809150509295509295909350565b6000806000606084860312156144f9578081fd5b833561450481615050565b9250602084013561451481615050565b9150604084013567ffffffffffffffff81111561452f578182fd5b840160608187031215614540578182fd5b809150509250925092565b60008060006060848603121561455f578081fd5b833561456a81615050565b9250602084013561457a81615050565b929592945050506040919091013590565b6000806000806000608086880312156145a2578283fd5b85356145ad81615050565b945060208601356145bd81615050565b935060408601359250606086013567ffffffffffffffff8111156145df578182fd5b6145eb888289016142bb565b969995985093965092949392505050565b60008060008060808587031215614611578182fd5b843561461c81615050565b935060208581013561462d81615050565b935060408601359250606086013567ffffffffffffffff80821115614650578384fd5b818801915088601f830112614663578384fd5b8135818111156146755761467561503a565b61468784601f19601f84011601614d46565b9150808252898482850101111561469c578485fd5b8084840185840137810190920192909252939692955090935050565b600080600080608085870312156146cd578182fd5b84356146d881615050565b935060208501356146e881615050565b925060408501359150606085013567ffffffffffffffff81111561470a578182fd5b85016040818803121561471b578182fd5b939692955090935050565b6000806000806080858703121561473b578182fd5b843561474681615050565b9350602085013561475681615050565b925060408501359150606085013567ffffffffffffffff80821115614779578283fd5b9086019060c0828903121561478c578283fd5b61479660c0614d46565b8235828111156147a4578485fd5b6147b08a8286016141ea565b8252506020830135828111156147c4578485fd5b6147d08a8286016141ea565b6020830152506040830135828111156147e7578485fd5b6147f38a828601614251565b60408301525060608301358281111561480a578485fd5b6148168a828601614251565b60608301525060808301358281111561482d578485fd5b6148398a828601614251565b60808301525060a083013560a082015280935050505092959194509250565b6000806040838503121561486a578182fd5b823561487581615050565b9150614883602084016142ab565b90509250929050565b6000806040838503121561489e578182fd5b82356148a981615050565b946020939093013593505050565b6000602082840312156148c8578081fd5b8135611f7581615065565b6000602082840312156148e4578081fd5b8151611f7581615065565b600060208284031215614900578081fd5b5035919050565b60008060408385031215614919578182fd5b82359150602083013567ffffffffffffffff811115614936578182fd5b61494285828601614251565b9150509250929050565b6000815180845260208085019450848183028601828601855b8581101561424457838303895261497d8383516149dc565b98850198925090840190600101614965565b60008284527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156149c0578081fd5b6020830280836020870137939093016020019283525090919050565b6000815180845260208085019450808401835b83811015614a0b578151875295820195908201906001016149ef565b509495945050505050565b60008151808452614a2e816020860160208601614f5c565b601f01601f19169290920160200192915050565b60007f697066733a2f2f6261667962656900000000000000000000000000000000000082528251614a7a81600e850160208701614f5c565b7f2f00000000000000000000000000000000000000000000000000000000000000600e9390910192830152507f6573746174652e6a736f6e000000000000000000000000000000000000000000600f820152601a01919050565b60006001600160a01b03808716835280861660208401525060806040830152614b0060808301856149dc565b8281036060840152614b128185614a16565b979650505050505050565b60006001600160a01b03808616835280851660208401525060806040830152614b4960808301846149dc565b82810360609093019290925281526020019392505050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152612f0f6080830184614a16565b600060208252611f7560208301846149dc565b600060208252611f756020830184614a16565b600060208252614bc98384614d9b565b60606020850152614bde60808501828461498f565b915050614bee6020850185614d9b565b601f19858403016040860152614c0583828461498f565b92505050604084013560608401528091505092915050565b600060208252825160406020840152614c3960608401826149dc565b90506020840151601f19848303016040850152613f9882826149dc565b600060208252825160c06020840152614c7260e084018261494c565b90506020840151601f1980858403016040860152614c90838361494c565b92506040860151915080858403016060860152614cad83836149dc565b92506060860151915080858403016080860152614cca83836149dc565b925060808601519150808584030160a086015250614ce882826149dc565b91505060a084015160c08401528091505092915050565b6000808335601e19843603018112614d15578283fd5b83018035915067ffffffffffffffff821115614d2f578283fd5b602090810192508102360382131561324b57600080fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614d6f57614d6f61503a565b604052919050565b600067ffffffffffffffff821115614d9157614d9161503a565b5060209081020190565b6000808335601e19843603018112614db1578283fd5b830160208101925035905067ffffffffffffffff811115614dd157600080fd5b60208102360383131561324b57600080fd5b60008219821115614df657614df661500e565b500190565b600082614e0a57614e0a615024565b500490565b80825b6001808611614e215750614e4c565b818704821115614e3357614e3361500e565b80861615614e4057918102915b9490941c938002614e12565b94509492505050565b6000611f7560001960ff851684600082614e7157506001611f75565b81614e7e57506000611f75565b8160018114614e945760028114614e9e57614ecb565b6001915050611f75565b60ff841115614eaf57614eaf61500e565b6001841b915084821115614ec557614ec561500e565b50611f75565b5060208310610133831016604e8410600b8410161715614efe575081810a83811115614ef957614ef961500e565b611f75565b614f0b8484846001614e0f565b808604821115614f1d57614f1d61500e565b02949350505050565b6000816000190483118215151615614f4057614f4061500e565b500290565b600082821015614f5757614f5761500e565b500390565b60005b83811015614f77578181015183820152602001614f5f565b83811115611eeb5750506000910152565b600081614f9757614f9761500e565b506000190190565b600061ffff80831681811415614fb757614fb761500e565b6001019392505050565b6000600019821415614fd557614fd561500e565b5060010190565b600067ffffffffffffffff80831681811415614fb757614fb761500e565b60008261500957615009615024565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146141ce57600080fd5b6001600160e01b0319811681146141ce57600080fdfea26469706673582212207d5730ac740cb3b35e9f646824a237e6dd5cef6503ad0ce906f1cf08f615ce6864736f6c63430008020033
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.