ERC-721
Overview
Max Total Supply
166 TNTCL
Holders
75
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
3 TNTCLLoading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
Tentacular
Compiler Version
v0.8.11+commit.d7f03943
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.11; // simple ownership check, ownership transfer + noContracts modifier import {SecuredBase} from "../src/base/SecuredBase.sol"; // https://github.com/chiru-labs/ERC721A import {ERC721AQueryable, ERC721A} from "../src/erc721a/extensions/ERC721AQueryable.sol"; // https://github.com/fx-portal import {FxBaseRootTunnel} from "../src/fx-portal/tunnel/FxBaseRootTunnel.sol"; contract Tentacular is ERC721AQueryable, SecuredBase, FxBaseRootTunnel { event RequestSend(string cmd, address wallet, uint[] tokenIds); bytes32 public constant BOUND = keccak256("BOUND"); bytes32 public constant UNBOUND = keccak256("UNBOUND"); uint constant MAX_SUPPLY = 5556; address salesContractAddress; string baseURI; bool public bondsEnabled; error MaxSupplyReached(); error NotSalesContract(); error BondsDisabled(); error AlreadyBound(uint tokenId); error NotBound(uint tokenId); error NotAnOwner(); mapping(uint => bool) public tokenIdToBound; constructor( address _checkpointManager, address _fxRoot, string memory name, string memory symbol ) FxBaseRootTunnel(_checkpointManager, _fxRoot) ERC721A(name, symbol) {} //////////////////////////////////////////////////////////////////////////////// //// USER ACTIONS //////////////////////////////////////////////////////////////////////////////// /** @dev mint amount of tokens to wallet @notice can be called from the sales contract only @param wallet wallet to receive tokens @param amount of tokens to be minted */ function mint(address wallet, uint amount) external salesContractOnly { if (_totalMinted() + amount > MAX_SUPPLY) revert MaxSupplyReached(); _mint(wallet, amount); } /** @dev bound the specified tokens to BerryJuicer @notice can be called when bondsEnabled only, sends the request via bridge to Polygon network @param tokenIds tokens to be bound */ function bound(uint[] calldata tokenIds) external onlyBondsEnabled noContracts { for (uint i;i<tokenIds.length;i++) { if (ownerOf(tokenIds[i])!=msg.sender) revert NotAnOwner(); if (tokenIdToBound[tokenIds[i]]) revert AlreadyBound(tokenIds[i]); tokenIdToBound[tokenIds[i]]=true; } bytes memory message = abi.encode(BOUND, abi.encode(msg.sender, tokenIds)); emit RequestSend("BOUND", msg.sender, tokenIds); _sendMessageToChild(message); } /** @dev unbound the specified tokens from BerryJuicer @notice sends the request via bridge to Polygon network @param tokenIds tokens to be unbound */ function unbound(uint[] calldata tokenIds) external noContracts { for (uint i;i<tokenIds.length;i++) { if (ownerOf(tokenIds[i])!=msg.sender) revert NotAnOwner(); if (tokenIdToBound[tokenIds[i]]==false) revert NotBound(tokenIds[i]); tokenIdToBound[tokenIds[i]]=false; } bytes memory message = abi.encode(UNBOUND, abi.encode(msg.sender, tokenIds)); emit RequestSend("UNBOUND", msg.sender, tokenIds); _sendMessageToChild(message); } //////////////////////////////////////////////////////////////////////////////// //// OWNER ONLY //////////////////////////////////////////////////////////////////////////////// /** @dev set the base address for token URI @param URI base URI to use */ function setBaseTokenURI(string calldata URI) external onlyOwner { baseURI = URI; } /** @dev set the sales contract address @notice used for salesContractOnly modifier checks @param _salesContractAddress sales contract address */ function setSalesContract(address _salesContractAddress) external onlyOwner { salesContractAddress=_salesContractAddress; } /** @dev set the bound function status @param status true to turn it on, false to turn it off */ function setBondsEnabled(bool status) external onlyOwner { bondsEnabled=status; } //////////////////////////////////////////////////////////////////////////////// //// OVERRIDES //////////////////////////////////////////////////////////////////////////////// /** @dev handle message from the bridge @notice not used, the polygon contract connected send no messages @param message message to be handled */ function _processMessageFromChild(bytes memory message) internal override { // Not used } /** @dev set child tunnel address @notice override to keep the possibility to change it anytime @param _fxChildTunnel child tunnel address */ function setFxChildTunnel(address _fxChildTunnel) public virtual override onlyOwner { fxChildTunnel = _fxChildTunnel; } /** @dev returns the baseURI @notice override to return variable we can change in setBaseTokenURI */ function _baseURI() internal view override returns (string memory) { return baseURI; } /** @dev called before token is transfered, minted or burned @notice override to unbound token automatically during the transfer */ function _beforeTokenTransfers( address from, address, // to, uint256 startTokenId, uint256 // quantity ) internal virtual override { if (tokenIdToBound[startTokenId]) { tokenIdToBound[startTokenId] = false; uint[] memory tokens = new uint[](1); tokens[0]=startTokenId; bytes memory message = abi.encode(UNBOUND, abi.encode(from, tokens)); emit RequestSend("UNBOUND", from, tokens); _sendMessageToChild(message); } } //////////////////////////////////////////////////////////////////////////////// //// MODIFIERS //////////////////////////////////////////////////////////////////////////////// /** @dev allow method to be executed only if bondsEnabled */ modifier onlyBondsEnabled() { if (!bondsEnabled) revert BondsDisabled(); _; } /** @dev allow method to be executed only if caller is salesContract */ modifier salesContractOnly() { if (msg.sender!=salesContractAddress) revert NotSalesContract(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.11; contract SecuredBase { address public owner; error NoContractsAllowed(); error NotContractOwner(); constructor() { owner=msg.sender; } function transferOwnership(address newOwner) external onlyOwner { owner=newOwner; } modifier onlyOwner() { if (msg.sender!=owner) revert NotContractOwner(); _; } modifier noContracts() { uint256 size = 0; address acc = msg.sender; assembly { size := extcodesize(acc)} if ((msg.sender != tx.origin) || (size != 0)) revert NoContractsAllowed(); _; } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.2 // Creator: Chiru Labs pragma solidity ^0.8.4; import './IERC721AQueryable.sol'; import '../ERC721A.sol'; /** * @title ERC721AQueryable. * * @dev ERC721A subclass with convenience query functions. */ abstract contract ERC721AQueryable is ERC721A, IERC721AQueryable { /** * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. * * If the `tokenId` is out of bounds: * * - `addr = address(0)` * - `startTimestamp = 0` * - `burned = false` * - `extraData = 0` * * If the `tokenId` is burned: * * - `addr = <Address of owner before token was burned>` * - `startTimestamp = <Timestamp when token was burned>` * - `burned = true` * - `extraData = <Extra data when token was burned>` * * Otherwise: * * - `addr = <Address of owner>` * - `startTimestamp = <Timestamp of start of ownership>` * - `burned = false` * - `extraData = <Extra data at start of ownership>` */ function explicitOwnershipOf(uint256 tokenId) public view virtual override returns (TokenOwnership memory) { TokenOwnership memory ownership; if (tokenId < _startTokenId() || tokenId >= _nextTokenId()) { return ownership; } ownership = _ownershipAt(tokenId); if (ownership.burned) { return ownership; } return _ownershipOf(tokenId); } /** * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. * See {ERC721AQueryable-explicitOwnershipOf} */ function explicitOwnershipsOf(uint256[] calldata tokenIds) external view virtual override returns (TokenOwnership[] memory) { unchecked { uint256 tokenIdsLength = tokenIds.length; TokenOwnership[] memory ownerships = new TokenOwnership[](tokenIdsLength); for (uint256 i; i != tokenIdsLength; ++i) { ownerships[i] = explicitOwnershipOf(tokenIds[i]); } return ownerships; } } /** * @dev Returns an array of token IDs owned by `owner`, * in the range [`start`, `stop`) * (i.e. `start <= tokenId < stop`). * * This function allows for tokens to be queried if the collection * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. * * Requirements: * * - `start < stop` */ function tokensOfOwnerIn( address owner, uint256 start, uint256 stop ) external view virtual override returns (uint256[] memory) { unchecked { if (start >= stop) revert InvalidQueryRange(); uint256 tokenIdsIdx; uint256 stopLimit = _nextTokenId(); // Set `start = max(start, _startTokenId())`. if (start < _startTokenId()) { start = _startTokenId(); } // Set `stop = min(stop, stopLimit)`. if (stop > stopLimit) { stop = stopLimit; } uint256 tokenIdsMaxLength = balanceOf(owner); // Set `tokenIdsMaxLength = min(balanceOf(owner), stop - start)`, // to cater for cases where `balanceOf(owner)` is too big. if (start < stop) { uint256 rangeLength = stop - start; if (rangeLength < tokenIdsMaxLength) { tokenIdsMaxLength = rangeLength; } } else { tokenIdsMaxLength = 0; } uint256[] memory tokenIds = new uint256[](tokenIdsMaxLength); if (tokenIdsMaxLength == 0) { return tokenIds; } // We need to call `explicitOwnershipOf(start)`, // because the slot at `start` may not be initialized. TokenOwnership memory ownership = explicitOwnershipOf(start); address currOwnershipAddr; // If the starting slot exists (i.e. not burned), initialize `currOwnershipAddr`. // `ownership.address` will not be zero, as `start` is clamped to the valid token ID range. if (!ownership.burned) { currOwnershipAddr = ownership.addr; } for (uint256 i = start; i != stop && tokenIdsIdx != tokenIdsMaxLength; ++i) { ownership = _ownershipAt(i); if (ownership.burned) { continue; } if (ownership.addr != address(0)) { currOwnershipAddr = ownership.addr; } if (currOwnershipAddr == owner) { tokenIds[tokenIdsIdx++] = i; } } // Downsize the array to fit. assembly { mstore(tokenIds, tokenIdsIdx) } return tokenIds; } } /** * @dev Returns an array of token IDs owned by `owner`. * * This function scans the ownership mapping and is O(`totalSupply`) in complexity. * It is meant to be called off-chain. * * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into * multiple smaller scans if the collection is large enough to cause * an out-of-gas error (10K collections should be fine). */ function tokensOfOwner(address owner) external view virtual override returns (uint256[] memory) { unchecked { uint256 tokenIdsIdx; address currOwnershipAddr; uint256 tokenIdsLength = balanceOf(owner); uint256[] memory tokenIds = new uint256[](tokenIdsLength); TokenOwnership memory ownership; for (uint256 i = _startTokenId(); tokenIdsIdx != tokenIdsLength; ++i) { ownership = _ownershipAt(i); if (ownership.burned) { continue; } if (ownership.addr != address(0)) { currOwnershipAddr = ownership.addr; } if (currOwnershipAddr == owner) { tokenIds[tokenIdsIdx++] = i; } } return tokenIds; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {RLPReader} from "../lib/RLPReader.sol"; import {MerklePatriciaProof} from "../lib/MerklePatriciaProof.sol"; import {Merkle} from "../lib/Merkle.sol"; import "../lib/ExitPayloadReader.sol"; interface IFxStateSender { function sendMessageToChild(address _receiver, bytes calldata _data) external; } contract ICheckpointManager { struct HeaderBlock { bytes32 root; uint256 start; uint256 end; uint256 createdAt; address proposer; } /** * @notice mapping of checkpoint header numbers to block details * @dev These checkpoints are submited by plasma contracts */ mapping(uint256 => HeaderBlock) public headerBlocks; } abstract contract FxBaseRootTunnel { using RLPReader for RLPReader.RLPItem; using Merkle for bytes32; using ExitPayloadReader for bytes; using ExitPayloadReader for ExitPayloadReader.ExitPayload; using ExitPayloadReader for ExitPayloadReader.Log; using ExitPayloadReader for ExitPayloadReader.LogTopics; using ExitPayloadReader for ExitPayloadReader.Receipt; // keccak256(MessageSent(bytes)) bytes32 public constant SEND_MESSAGE_EVENT_SIG = 0x8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b036; // state sender contract IFxStateSender public fxRoot; // root chain manager ICheckpointManager public checkpointManager; // child tunnel contract which receives and sends messages address public fxChildTunnel; // storage to avoid duplicate exits mapping(bytes32 => bool) public processedExits; constructor(address _checkpointManager, address _fxRoot) { checkpointManager = ICheckpointManager(_checkpointManager); fxRoot = IFxStateSender(_fxRoot); } // set fxChildTunnel if not set already function setFxChildTunnel(address _fxChildTunnel) public virtual { require(fxChildTunnel == address(0x0), "FxBaseRootTunnel: CHILD_TUNNEL_ALREADY_SET"); fxChildTunnel = _fxChildTunnel; } /** * @notice Send bytes message to Child Tunnel * @param message bytes message that will be sent to Child Tunnel * some message examples - * abi.encode(tokenId); * abi.encode(tokenId, tokenMetadata); * abi.encode(messageType, messageData); */ function _sendMessageToChild(bytes memory message) internal { fxRoot.sendMessageToChild(fxChildTunnel, message); } function _validateAndExtractMessage(bytes memory inputData) internal returns (bytes memory) { ExitPayloadReader.ExitPayload memory payload = inputData.toExitPayload(); bytes memory branchMaskBytes = payload.getBranchMaskAsBytes(); uint256 blockNumber = payload.getBlockNumber(); // checking if exit has already been processed // unique exit is identified using hash of (blockNumber, branchMask, receiptLogIndex) bytes32 exitHash = keccak256( abi.encodePacked( blockNumber, // first 2 nibbles are dropped while generating nibble array // this allows branch masks that are valid but bypass exitHash check (changing first 2 nibbles only) // so converting to nibble array and then hashing it MerklePatriciaProof._getNibbleArray(branchMaskBytes), payload.getReceiptLogIndex() ) ); require(processedExits[exitHash] == false, "FxRootTunnel: EXIT_ALREADY_PROCESSED"); processedExits[exitHash] = true; ExitPayloadReader.Receipt memory receipt = payload.getReceipt(); ExitPayloadReader.Log memory log = receipt.getLog(); // check child tunnel require(fxChildTunnel == log.getEmitter(), "FxRootTunnel: INVALID_FX_CHILD_TUNNEL"); bytes32 receiptRoot = payload.getReceiptRoot(); // verify receipt inclusion require( MerklePatriciaProof.verify(receipt.toBytes(), branchMaskBytes, payload.getReceiptProof(), receiptRoot), "FxRootTunnel: INVALID_RECEIPT_PROOF" ); // verify checkpoint inclusion _checkBlockMembershipInCheckpoint( blockNumber, payload.getBlockTime(), payload.getTxRoot(), receiptRoot, payload.getHeaderNumber(), payload.getBlockProof() ); ExitPayloadReader.LogTopics memory topics = log.getTopics(); require( bytes32(topics.getField(0).toUint()) == SEND_MESSAGE_EVENT_SIG, // topic0 is event sig "FxRootTunnel: INVALID_SIGNATURE" ); // received message data bytes memory message = abi.decode(log.getData(), (bytes)); // event decodes params again, so decoding bytes to get message return message; } function _checkBlockMembershipInCheckpoint( uint256 blockNumber, uint256 blockTime, bytes32 txRoot, bytes32 receiptRoot, uint256 headerNumber, bytes memory blockProof ) private view returns (uint256) { (bytes32 headerRoot, uint256 startBlock, , uint256 createdAt, ) = checkpointManager.headerBlocks(headerNumber); require( keccak256(abi.encodePacked(blockNumber, blockTime, txRoot, receiptRoot)).checkMembership( blockNumber - startBlock, headerRoot, blockProof ), "FxRootTunnel: INVALID_HEADER" ); return createdAt; } /** * @notice receive message from L2 to L1, validated by proof * @dev This function verifies if the transaction actually happened on child chain * * @param inputData RLP encoded data of the reference tx containing following list of fields * 0 - headerNumber - Checkpoint header block number containing the reference tx * 1 - blockProof - Proof that the block header (in the child chain) is a leaf in the submitted merkle root * 2 - blockNumber - Block number containing the reference tx on child chain * 3 - blockTime - Reference tx block time * 4 - txRoot - Transactions root of block * 5 - receiptRoot - Receipts root of block * 6 - receipt - Receipt of the reference transaction * 7 - receiptProof - Merkle proof of the reference receipt * 8 - branchMask - 32 bits denoting the path of receipt in merkle tree * 9 - receiptLogIndex - Log Index to read from the receipt */ function receiveMessage(bytes memory inputData) public virtual { bytes memory message = _validateAndExtractMessage(inputData); _processMessageFromChild(message); } /** * @notice Process message received from Child Tunnel * @dev function needs to be implemented to handle message as per requirement * This is called by onStateReceive function. * Since it is called via a system call, any event will not be emitted during its execution. * @param message bytes message that was sent from Child Tunnel */ function _processMessageFromChild(bytes memory message) internal virtual; }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.2 // Creator: Chiru Labs pragma solidity ^0.8.4; import '../IERC721A.sol'; /** * @dev Interface of ERC721AQueryable. */ interface IERC721AQueryable is IERC721A { /** * Invalid query range (`start` >= `stop`). */ error InvalidQueryRange(); /** * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. * * If the `tokenId` is out of bounds: * * - `addr = address(0)` * - `startTimestamp = 0` * - `burned = false` * - `extraData = 0` * * If the `tokenId` is burned: * * - `addr = <Address of owner before token was burned>` * - `startTimestamp = <Timestamp when token was burned>` * - `burned = true` * - `extraData = <Extra data when token was burned>` * * Otherwise: * * - `addr = <Address of owner>` * - `startTimestamp = <Timestamp of start of ownership>` * - `burned = false` * - `extraData = <Extra data at start of ownership>` */ function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory); /** * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. * See {ERC721AQueryable-explicitOwnershipOf} */ function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory); /** * @dev Returns an array of token IDs owned by `owner`, * in the range [`start`, `stop`) * (i.e. `start <= tokenId < stop`). * * This function allows for tokens to be queried if the collection * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. * * Requirements: * * - `start < stop` */ function tokensOfOwnerIn( address owner, uint256 start, uint256 stop ) external view returns (uint256[] memory); /** * @dev Returns an array of token IDs owned by `owner`. * * This function scans the ownership mapping and is O(`totalSupply`) in complexity. * It is meant to be called off-chain. * * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into * multiple smaller scans if the collection is large enough to cause * an out-of-gas error (10K collections should be fine). */ function tokensOfOwner(address owner) external view returns (uint256[] memory); }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.2 // Creator: Chiru Labs pragma solidity ^0.8.4; import './IERC721A.sol'; /** * @dev Interface of ERC721 token receiver. */ interface ERC721A__IERC721Receiver { function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); } /** * @title ERC721A * * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721) * Non-Fungible Token Standard, including the Metadata extension. * Optimized for lower gas during batch mints. * * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...) * starting from `_startTokenId()`. * * Assumptions: * * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply. * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256). */ contract ERC721A is IERC721A { // Reference type for token approval. struct TokenApprovalRef { address value; } // ============================================================= // CONSTANTS // ============================================================= // Mask of an entry in packed address data. uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; // The bit position of `numberMinted` in packed address data. uint256 private constant _BITPOS_NUMBER_MINTED = 64; // The bit position of `numberBurned` in packed address data. uint256 private constant _BITPOS_NUMBER_BURNED = 128; // The bit position of `aux` in packed address data. uint256 private constant _BITPOS_AUX = 192; // Mask of all 256 bits in packed address data except the 64 bits for `aux`. uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; // The bit position of `startTimestamp` in packed ownership. uint256 private constant _BITPOS_START_TIMESTAMP = 160; // The bit mask of the `burned` bit in packed ownership. uint256 private constant _BITMASK_BURNED = 1 << 224; // The bit position of the `nextInitialized` bit in packed ownership. uint256 private constant _BITPOS_NEXT_INITIALIZED = 225; // The bit mask of the `nextInitialized` bit in packed ownership. uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225; // The bit position of `extraData` in packed ownership. uint256 private constant _BITPOS_EXTRA_DATA = 232; // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; // The mask of the lower 160 bits for addresses. uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1; // The maximum `quantity` that can be minted with {_mintERC2309}. // This limit is to prevent overflows on the address data entries. // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309} // is required to cause an overflow, which is unrealistic. uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; // The `Transfer` event signature is given by: // `keccak256(bytes("Transfer(address,address,uint256)"))`. bytes32 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; // ============================================================= // STORAGE // ============================================================= // The next token ID to be minted. uint256 private _currentIndex; // The number of tokens burned. uint256 private _burnCounter; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to ownership details // An empty struct value does not necessarily mean the token is unowned. // See {_packedOwnershipOf} implementation for details. // // Bits Layout: // - [0..159] `addr` // - [160..223] `startTimestamp` // - [224] `burned` // - [225] `nextInitialized` // - [232..255] `extraData` mapping(uint256 => uint256) private _packedOwnerships; // Mapping owner address to address data. // // Bits Layout: // - [0..63] `balance` // - [64..127] `numberMinted` // - [128..191] `numberBurned` // - [192..255] `aux` mapping(address => uint256) private _packedAddressData; // Mapping from token ID to approved address. mapping(uint256 => TokenApprovalRef) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; // ============================================================= // CONSTRUCTOR // ============================================================= constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; _currentIndex = _startTokenId(); } // ============================================================= // TOKEN COUNTING OPERATIONS // ============================================================= /** * @dev Returns the starting token ID. * To change the starting token ID, please override this function. */ function _startTokenId() internal view virtual returns (uint256) { return 0; } /** * @dev Returns the next token ID to be minted. */ function _nextTokenId() internal view virtual returns (uint256) { return _currentIndex; } /** * @dev Returns the total number of tokens in existence. * Burned tokens will reduce the count. * To get the total number of tokens minted, please see {_totalMinted}. */ function totalSupply() public view virtual override returns (uint256) { // Counter underflow is impossible as _burnCounter cannot be incremented // more than `_currentIndex - _startTokenId()` times. unchecked { return _currentIndex - _burnCounter - _startTokenId(); } } /** * @dev Returns the total amount of tokens minted in the contract. */ function _totalMinted() internal view virtual returns (uint256) { // Counter underflow is impossible as `_currentIndex` does not decrement, // and it is initialized to `_startTokenId()`. unchecked { return _currentIndex - _startTokenId(); } } /** * @dev Returns the total number of tokens burned. */ function _totalBurned() internal view virtual returns (uint256) { return _burnCounter; } // ============================================================= // ADDRESS DATA OPERATIONS // ============================================================= /** * @dev Returns the number of tokens in `owner`'s account. */ function balanceOf(address owner) public view virtual override returns (uint256) { if (owner == address(0)) revert BalanceQueryForZeroAddress(); return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY; } /** * Returns the number of tokens minted by `owner`. */ function _numberMinted(address owner) internal view returns (uint256) { return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY; } /** * Returns the number of tokens burned by or on behalf of `owner`. */ function _numberBurned(address owner) internal view returns (uint256) { return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY; } /** * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). */ function _getAux(address owner) internal view returns (uint64) { return uint64(_packedAddressData[owner] >> _BITPOS_AUX); } /** * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). * If there are multiple variables, please pack them into a uint64. */ function _setAux(address owner, uint64 aux) internal virtual { uint256 packed = _packedAddressData[owner]; uint256 auxCasted; // Cast `aux` with assembly to avoid redundant masking. assembly { auxCasted := aux } packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX); _packedAddressData[owner] = packed; } // ============================================================= // IERC165 // ============================================================= /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * to learn more about how these ids are created. * * This function call must use less than 30000 gas. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { // The interface IDs are constants representing the first 4 bytes // of the XOR of all function selectors in the interface. // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165) // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`) return interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. } // ============================================================= // IERC721Metadata // ============================================================= /** * @dev Returns the token collection name. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the token collection symbol. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { if (!_exists(tokenId)) revert URIQueryForNonexistentToken(); string memory baseURI = _baseURI(); return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, it can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ''; } // ============================================================= // OWNERSHIPS OPERATIONS // ============================================================= /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { return address(uint160(_packedOwnershipOf(tokenId))); } /** * @dev Gas spent here starts off proportional to the maximum mint batch size. * It gradually moves to O(1) as tokens get transferred around over time. */ function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) { return _unpackedOwnership(_packedOwnershipOf(tokenId)); } /** * @dev Returns the unpacked `TokenOwnership` struct at `index`. */ function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) { return _unpackedOwnership(_packedOwnerships[index]); } /** * @dev Initializes the ownership slot minted at `index` for efficiency purposes. */ function _initializeOwnershipAt(uint256 index) internal virtual { if (_packedOwnerships[index] == 0) { _packedOwnerships[index] = _packedOwnershipOf(index); } } /** * Returns the packed ownership data of `tokenId`. */ function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) { uint256 curr = tokenId; unchecked { if (_startTokenId() <= curr) if (curr < _currentIndex) { uint256 packed = _packedOwnerships[curr]; // If not burned. if (packed & _BITMASK_BURNED == 0) { // Invariant: // There will always be an initialized ownership slot // (i.e. `ownership.addr != address(0) && ownership.burned == false`) // before an unintialized ownership slot // (i.e. `ownership.addr == address(0) && ownership.burned == false`) // Hence, `curr` will not underflow. // // We can directly compare the packed value. // If the address is zero, packed will be zero. while (packed == 0) { packed = _packedOwnerships[--curr]; } return packed; } } } revert OwnerQueryForNonexistentToken(); } /** * @dev Returns the unpacked `TokenOwnership` struct from `packed`. */ function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { ownership.addr = address(uint160(packed)); ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP); ownership.burned = packed & _BITMASK_BURNED != 0; ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA); } /** * @dev Packs ownership data into a single uint256. */ function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) { assembly { // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. owner := and(owner, _BITMASK_ADDRESS) // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`. result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags)) } } /** * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. */ function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) { // For branchless setting of the `nextInitialized` flag. assembly { // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`. result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) } } // ============================================================= // APPROVAL OPERATIONS // ============================================================= /** * @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) public virtual override { address owner = ownerOf(tokenId); if (_msgSenderERC721A() != owner) if (!isApprovedForAll(owner, _msgSenderERC721A())) { revert ApprovalCallerNotOwnerNorApproved(); } _tokenApprovals[tokenId].value = to; emit Approval(owner, to, tokenId); } /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken(); return _tokenApprovals[tokenId].value; } /** * @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) public virtual override { _operatorApprovals[_msgSenderERC721A()][operator] = approved; emit ApprovalForAll(_msgSenderERC721A(), operator, approved); } /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted. See {_mint}. */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _startTokenId() <= tokenId && tokenId < _currentIndex && // If within bounds, _packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned. } /** * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`. */ function _isSenderApprovedOrOwner( address approvedAddress, address owner, address msgSender ) private pure returns (bool result) { assembly { // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. owner := and(owner, _BITMASK_ADDRESS) // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. msgSender := and(msgSender, _BITMASK_ADDRESS) // `msgSender == owner || msgSender == approvedAddress`. result := or(eq(msgSender, owner), eq(msgSender, approvedAddress)) } } /** * @dev Returns the storage slot and value for the approved address of `tokenId`. */ function _getApprovedSlotAndAddress(uint256 tokenId) private view returns (uint256 approvedAddressSlot, address approvedAddress) { TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId]; // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`. assembly { approvedAddressSlot := tokenApproval.slot approvedAddress := sload(approvedAddressSlot) } } // ============================================================= // TRANSFER OPERATIONS // ============================================================= /** * @dev Transfers `tokenId` from `from` to `to`. * * 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 ) public virtual override { uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner(); (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); // The nested ifs save around 20+ gas over a compound boolean condition. if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); if (to == address(0)) revert TransferToZeroAddress(); _beforeTokenTransfers(from, to, tokenId, 1); // Clear approvals from the previous owner. assembly { if approvedAddress { // This is equivalent to `delete _tokenApprovals[tokenId]`. sstore(approvedAddressSlot, 0) } } // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. unchecked { // We can directly increment and decrement the balances. --_packedAddressData[from]; // Updates: `balance -= 1`. ++_packedAddressData[to]; // Updates: `balance += 1`. // Updates: // - `address` to the next owner. // - `startTimestamp` to the timestamp of transfering. // - `burned` to `false`. // - `nextInitialized` to `true`. _packedOwnerships[tokenId] = _packOwnershipData( to, _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) ); // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { uint256 nextTokenId = tokenId + 1; // If the next slot's address is zero and not burned (i.e. packed value is zero). if (_packedOwnerships[nextTokenId] == 0) { // If the next slot is within bounds. if (nextTokenId != _currentIndex) { // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. _packedOwnerships[nextTokenId] = prevOwnershipPacked; } } } } emit Transfer(from, to, tokenId); _afterTokenTransfers(from, to, tokenId, 1); } /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ''); } /** * @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 memory _data ) public virtual override { transferFrom(from, to, tokenId); if (to.code.length != 0) if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { revert TransferToNonERC721ReceiverImplementer(); } } /** * @dev Hook that is called before a set of serially-ordered token IDs * are about to be transferred. This includes minting. * And also called before burning one token. * * `startTokenId` - the first token ID to be transferred. * `quantity` - the amount to be transferred. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, `tokenId` will be burned by `from`. * - `from` and `to` are never both zero. */ function _beforeTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual {} /** * @dev Hook that is called after a set of serially-ordered token IDs * have been transferred. This includes minting. * And also called after one token has been burned. * * `startTokenId` - the first token ID to be transferred. * `quantity` - the amount to be transferred. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been * transferred to `to`. * - When `from` is zero, `tokenId` has been minted for `to`. * - When `to` is zero, `tokenId` has been burned by `from`. * - `from` and `to` are never both zero. */ function _afterTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual {} /** * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract. * * `from` - Previous owner of the given token ID. * `to` - Target address that will receive the token. * `tokenId` - Token ID to be transferred. * `_data` - Optional data to send along with the call. * * Returns whether the call correctly returned the expected magic value. */ function _checkContractOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns ( bytes4 retval ) { return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert TransferToNonERC721ReceiverImplementer(); } else { assembly { revert(add(32, reason), mload(reason)) } } } } // ============================================================= // MINT OPERATIONS // ============================================================= /** * @dev Mints `quantity` tokens and transfers them to `to`. * * Requirements: * * - `to` cannot be the zero address. * - `quantity` must be greater than 0. * * Emits a {Transfer} event for each mint. */ function _mint(address to, uint256 quantity) internal virtual { uint256 startTokenId = _currentIndex; if (quantity == 0) revert MintZeroQuantity(); _beforeTokenTransfers(address(0), to, startTokenId, quantity); // Overflows are incredibly unrealistic. // `balance` and `numberMinted` have a maximum limit of 2**64. // `tokenId` has a maximum limit of 2**256. unchecked { // Updates: // - `balance += quantity`. // - `numberMinted += quantity`. // // We can directly add to the `balance` and `numberMinted`. _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); // Updates: // - `address` to the owner. // - `startTimestamp` to the timestamp of minting. // - `burned` to `false`. // - `nextInitialized` to `quantity == 1`. _packedOwnerships[startTokenId] = _packOwnershipData( to, _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) ); uint256 toMasked; uint256 end = startTokenId + quantity; // Use assembly to loop and emit the `Transfer` event for gas savings. // The duplicated `log4` removes an extra check and reduces stack juggling. // The assembly, together with the surrounding Solidity code, have been // delicately arranged to nudge the compiler into producing optimized opcodes. assembly { // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. toMasked := and(to, _BITMASK_ADDRESS) // Emit the `Transfer` event. log4( 0, // Start of data (0, since no data). 0, // End of data (0, since no data). _TRANSFER_EVENT_SIGNATURE, // Signature. 0, // `address(0)`. toMasked, // `to`. startTokenId // `tokenId`. ) for { let tokenId := add(startTokenId, 1) } iszero(eq(tokenId, end)) { tokenId := add(tokenId, 1) } { // Emit the `Transfer` event. Similar to above. log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId) } } if (toMasked == 0) revert MintToZeroAddress(); _currentIndex = end; } _afterTokenTransfers(address(0), to, startTokenId, quantity); } /** * @dev Mints `quantity` tokens and transfers them to `to`. * * This function is intended for efficient minting only during contract creation. * * It emits only one {ConsecutiveTransfer} as defined in * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), * instead of a sequence of {Transfer} event(s). * * Calling this function outside of contract creation WILL make your contract * non-compliant with the ERC721 standard. * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 * {ConsecutiveTransfer} event is only permissible during contract creation. * * Requirements: * * - `to` cannot be the zero address. * - `quantity` must be greater than 0. * * Emits a {ConsecutiveTransfer} event. */ function _mintERC2309(address to, uint256 quantity) internal virtual { uint256 startTokenId = _currentIndex; if (to == address(0)) revert MintToZeroAddress(); if (quantity == 0) revert MintZeroQuantity(); if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit(); _beforeTokenTransfers(address(0), to, startTokenId, quantity); // Overflows are unrealistic due to the above check for `quantity` to be below the limit. unchecked { // Updates: // - `balance += quantity`. // - `numberMinted += quantity`. // // We can directly add to the `balance` and `numberMinted`. _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); // Updates: // - `address` to the owner. // - `startTimestamp` to the timestamp of minting. // - `burned` to `false`. // - `nextInitialized` to `quantity == 1`. _packedOwnerships[startTokenId] = _packOwnershipData( to, _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) ); emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); _currentIndex = startTokenId + quantity; } _afterTokenTransfers(address(0), to, startTokenId, quantity); } /** * @dev Safely mints `quantity` tokens and transfers them to `to`. * * Requirements: * * - If `to` refers to a smart contract, it must implement * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. * - `quantity` must be greater than 0. * * See {_mint}. * * Emits a {Transfer} event for each mint. */ function _safeMint( address to, uint256 quantity, bytes memory _data ) internal virtual { _mint(to, quantity); unchecked { if (to.code.length != 0) { uint256 end = _currentIndex; uint256 index = end - quantity; do { if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { revert TransferToNonERC721ReceiverImplementer(); } } while (index < end); // Reentrancy protection. if (_currentIndex != end) revert(); } } } /** * @dev Equivalent to `_safeMint(to, quantity, '')`. */ function _safeMint(address to, uint256 quantity) internal virtual { _safeMint(to, quantity, ''); } // ============================================================= // BURN OPERATIONS // ============================================================= /** * @dev Equivalent to `_burn(tokenId, false)`. */ function _burn(uint256 tokenId) internal virtual { _burn(tokenId, false); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId, bool approvalCheck) internal virtual { uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); address from = address(uint160(prevOwnershipPacked)); (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); if (approvalCheck) { // The nested ifs save around 20+ gas over a compound boolean condition. if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); } _beforeTokenTransfers(from, address(0), tokenId, 1); // Clear approvals from the previous owner. assembly { if approvedAddress { // This is equivalent to `delete _tokenApprovals[tokenId]`. sstore(approvedAddressSlot, 0) } } // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. unchecked { // Updates: // - `balance -= 1`. // - `numberBurned += 1`. // // We can directly decrement the balance, and increment the number burned. // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`. _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1; // Updates: // - `address` to the last owner. // - `startTimestamp` to the timestamp of burning. // - `burned` to `true`. // - `nextInitialized` to `true`. _packedOwnerships[tokenId] = _packOwnershipData( from, (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) ); // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { uint256 nextTokenId = tokenId + 1; // If the next slot's address is zero and not burned (i.e. packed value is zero). if (_packedOwnerships[nextTokenId] == 0) { // If the next slot is within bounds. if (nextTokenId != _currentIndex) { // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. _packedOwnerships[nextTokenId] = prevOwnershipPacked; } } } } emit Transfer(from, address(0), tokenId); _afterTokenTransfers(from, address(0), tokenId, 1); // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times. unchecked { _burnCounter++; } } // ============================================================= // EXTRA DATA OPERATIONS // ============================================================= /** * @dev Directly sets the extra data for the ownership data `index`. */ function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual { uint256 packed = _packedOwnerships[index]; if (packed == 0) revert OwnershipNotInitializedForExtraData(); uint256 extraDataCasted; // Cast `extraData` with assembly to avoid redundant masking. assembly { extraDataCasted := extraData } packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA); _packedOwnerships[index] = packed; } /** * @dev Called during each token transfer to set the 24bit `extraData` field. * Intended to be overridden by the cosumer contract. * * `previousExtraData` - the value of `extraData` before transfer. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, `tokenId` will be burned by `from`. * - `from` and `to` are never both zero. */ function _extraData( address from, address to, uint24 previousExtraData ) internal view virtual returns (uint24) {} /** * @dev Returns the next extra data for the packed ownership data. * The returned result is shifted into position. */ function _nextExtraData( address from, address to, uint256 prevOwnershipPacked ) private view returns (uint256) { uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA); return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA; } // ============================================================= // OTHER OPERATIONS // ============================================================= /** * @dev Returns the message sender (defaults to `msg.sender`). * * If you are writing GSN compatible contracts, you need to override this function. */ function _msgSenderERC721A() internal view virtual returns (address) { return msg.sender; } /** * @dev Converts a uint256 to its ASCII string decimal representation. */ function _toString(uint256 value) internal pure virtual returns (string memory str) { assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), // but we allocate 0x80 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 32-byte word to store the length, // and 3 32-byte words to store a maximum of 78 digits. Total: 0x20 + 3 * 0x20 = 0x80. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, str) // Cache the end of the memory to calculate the length later. let end := str // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. // prettier-ignore for { let temp := value } 1 {} { str := sub(str, 1) // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) // prettier-ignore if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.2 // Creator: Chiru Labs pragma solidity ^0.8.4; /** * @dev Interface of ERC721A. */ interface IERC721A { /** * The caller must own the token or be an approved operator. */ error ApprovalCallerNotOwnerNorApproved(); /** * The token does not exist. */ error ApprovalQueryForNonexistentToken(); /** * Cannot query the balance for the zero address. */ error BalanceQueryForZeroAddress(); /** * Cannot mint to the zero address. */ error MintToZeroAddress(); /** * The quantity of tokens minted must be more than zero. */ error MintZeroQuantity(); /** * The token does not exist. */ error OwnerQueryForNonexistentToken(); /** * The caller must own the token or be an approved operator. */ error TransferCallerNotOwnerNorApproved(); /** * The token must be owned by `from`. */ error TransferFromIncorrectOwner(); /** * Cannot safely transfer to a contract that does not implement the * ERC721Receiver interface. */ error TransferToNonERC721ReceiverImplementer(); /** * Cannot transfer to the zero address. */ error TransferToZeroAddress(); /** * The token does not exist. */ error URIQueryForNonexistentToken(); /** * The `quantity` minted with ERC2309 exceeds the safety limit. */ error MintERC2309QuantityExceedsLimit(); /** * The `extraData` cannot be set on an unintialized ownership slot. */ error OwnershipNotInitializedForExtraData(); // ============================================================= // STRUCTS // ============================================================= struct TokenOwnership { // The address of the owner. address addr; // Stores the start time of ownership with minimal overhead for tokenomics. uint64 startTimestamp; // Whether the token has been burned. bool burned; // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. uint24 extraData; } // ============================================================= // TOKEN COUNTERS // ============================================================= /** * @dev Returns the total number of tokens in existence. * Burned tokens will reduce the count. * To get the total number of tokens minted, please see {_totalMinted}. */ function totalSupply() external view returns (uint256); // ============================================================= // IERC165 // ============================================================= /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * to learn more about how these ids are created. * * This function call must use less than 30000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); // ============================================================= // IERC721 // ============================================================= /** * @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, bytes calldata data ) external; /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` 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 Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} * for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll}. */ function isApprovedForAll(address owner, address operator) external view returns (bool); // ============================================================= // IERC721Metadata // ============================================================= /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); // ============================================================= // IERC2309 // ============================================================= /** * @dev Emitted when tokens in `fromTokenId` to `toTokenId` * (inclusive) is transferred from `from` to `to`, as defined in the * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. * * See {_mintERC2309} for more details. */ event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); }
/* * @author Hamdi Allam [email protected] * Please reach out with any questions or concerns */ pragma solidity ^0.8.0; library RLPReader { uint8 constant STRING_SHORT_START = 0x80; uint8 constant STRING_LONG_START = 0xb8; uint8 constant LIST_SHORT_START = 0xc0; uint8 constant LIST_LONG_START = 0xf8; uint8 constant WORD_SIZE = 32; struct RLPItem { uint256 len; uint256 memPtr; } struct Iterator { RLPItem item; // Item that's being iterated over. uint256 nextPtr; // Position of the next item in the list. } /* * @dev Returns the next element in the iteration. Reverts if it has not next element. * @param self The iterator. * @return The next element in the iteration. */ function next(Iterator memory self) internal pure returns (RLPItem memory) { require(hasNext(self)); uint256 ptr = self.nextPtr; uint256 itemLength = _itemLength(ptr); self.nextPtr = ptr + itemLength; return RLPItem(itemLength, ptr); } /* * @dev Returns true if the iteration has more elements. * @param self The iterator. * @return true if the iteration has more elements. */ function hasNext(Iterator memory self) internal pure returns (bool) { RLPItem memory item = self.item; return self.nextPtr < item.memPtr + item.len; } /* * @param item RLP encoded bytes */ function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) { uint256 memPtr; assembly { memPtr := add(item, 0x20) } return RLPItem(item.length, memPtr); } /* * @dev Create an iterator. Reverts if item is not a list. * @param self The RLP item. * @return An 'Iterator' over the item. */ function iterator(RLPItem memory self) internal pure returns (Iterator memory) { require(isList(self)); uint256 ptr = self.memPtr + _payloadOffset(self.memPtr); return Iterator(self, ptr); } /* * @param item RLP encoded bytes */ function rlpLen(RLPItem memory item) internal pure returns (uint256) { return item.len; } /* * @param item RLP encoded bytes */ function payloadLen(RLPItem memory item) internal pure returns (uint256) { return item.len - _payloadOffset(item.memPtr); } /* * @param item RLP encoded list in bytes */ function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) { require(isList(item)); uint256 items = numItems(item); RLPItem[] memory result = new RLPItem[](items); uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 dataLen; for (uint256 i = 0; i < items; i++) { dataLen = _itemLength(memPtr); result[i] = RLPItem(dataLen, memPtr); memPtr = memPtr + dataLen; } return result; } // @return indicator whether encoded payload is a list. negate this function call for isData. function isList(RLPItem memory item) internal pure returns (bool) { if (item.len == 0) return false; uint8 byte0; uint256 memPtr = item.memPtr; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < LIST_SHORT_START) return false; return true; } /* * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory. * @return keccak256 hash of RLP encoded bytes. */ function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) { uint256 ptr = item.memPtr; uint256 len = item.len; bytes32 result; assembly { result := keccak256(ptr, len) } return result; } function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) { uint256 offset = _payloadOffset(item.memPtr); uint256 memPtr = item.memPtr + offset; uint256 len = item.len - offset; // data length return (memPtr, len); } /* * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory. * @return keccak256 hash of the item payload. */ function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) { (uint256 memPtr, uint256 len) = payloadLocation(item); bytes32 result; assembly { result := keccak256(memPtr, len) } return result; } /** RLPItem conversions into data types **/ // @returns raw rlp encoding in bytes function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) { bytes memory result = new bytes(item.len); if (result.length == 0) return result; uint256 ptr; assembly { ptr := add(0x20, result) } copy(item.memPtr, ptr, item.len); return result; } // any non-zero byte is considered true function toBoolean(RLPItem memory item) internal pure returns (bool) { require(item.len == 1); uint256 result; uint256 memPtr = item.memPtr; assembly { result := byte(0, mload(memPtr)) } return result == 0 ? false : true; } function toAddress(RLPItem memory item) internal pure returns (address) { // 1 byte for the length prefix require(item.len == 21); return address(uint160(toUint(item))); } function toUint(RLPItem memory item) internal pure returns (uint256) { require(item.len > 0 && item.len <= 33); uint256 offset = _payloadOffset(item.memPtr); uint256 len = item.len - offset; uint256 result; uint256 memPtr = item.memPtr + offset; assembly { result := mload(memPtr) // shfit to the correct location if neccesary if lt(len, 32) { result := div(result, exp(256, sub(32, len))) } } return result; } // enforces 32 byte length function toUintStrict(RLPItem memory item) internal pure returns (uint256) { // one byte prefix require(item.len == 33); uint256 result; uint256 memPtr = item.memPtr + 1; assembly { result := mload(memPtr) } return result; } function toBytes(RLPItem memory item) internal pure returns (bytes memory) { require(item.len > 0); uint256 offset = _payloadOffset(item.memPtr); uint256 len = item.len - offset; // data length bytes memory result = new bytes(len); uint256 destPtr; assembly { destPtr := add(0x20, result) } copy(item.memPtr + offset, destPtr, len); return result; } /* * Private Helpers */ // @return number of payload items inside an encoded list. function numItems(RLPItem memory item) private pure returns (uint256) { if (item.len == 0) return 0; uint256 count = 0; uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 endPtr = item.memPtr + item.len; while (currPtr < endPtr) { currPtr = currPtr + _itemLength(currPtr); // skip over an item count++; } return count; } // @return entire rlp item byte length function _itemLength(uint256 memPtr) private pure returns (uint256) { uint256 itemLen; uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) itemLen = 1; else if (byte0 < STRING_LONG_START) itemLen = byte0 - STRING_SHORT_START + 1; else if (byte0 < LIST_SHORT_START) { assembly { let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is memPtr := add(memPtr, 1) // skip over the first byte /* 32 byte word size */ let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len itemLen := add(dataLen, add(byteLen, 1)) } } else if (byte0 < LIST_LONG_START) { itemLen = byte0 - LIST_SHORT_START + 1; } else { assembly { let byteLen := sub(byte0, 0xf7) memPtr := add(memPtr, 1) let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length itemLen := add(dataLen, add(byteLen, 1)) } } return itemLen; } // @return number of bytes until the data function _payloadOffset(uint256 memPtr) private pure returns (uint256) { uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) return 0; else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) return 1; else if (byte0 < LIST_SHORT_START) // being explicit return byte0 - (STRING_LONG_START - 1) + 1; else return byte0 - (LIST_LONG_START - 1) + 1; } /* * @param src Pointer to source * @param dest Pointer to destination * @param len Amount of memory to copy from the source */ function copy( uint256 src, uint256 dest, uint256 len ) private pure { if (len == 0) return; // copy as many word sizes as possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } src += WORD_SIZE; dest += WORD_SIZE; } if (len == 0) return; // left over bytes. Mask is used to remove unwanted bytes from the word uint256 mask = 256**(WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) // zero out src let destpart := and(mload(dest), mask) // retrieve the bytes mstore(dest, or(destpart, srcpart)) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {RLPReader} from "./RLPReader.sol"; library MerklePatriciaProof { /* * @dev Verifies a merkle patricia proof. * @param value The terminating value in the trie. * @param encodedPath The path in the trie leading to value. * @param rlpParentNodes The rlp encoded stack of nodes. * @param root The root hash of the trie. * @return The boolean validity of the proof. */ function verify( bytes memory value, bytes memory encodedPath, bytes memory rlpParentNodes, bytes32 root ) internal pure returns (bool) { RLPReader.RLPItem memory item = RLPReader.toRlpItem(rlpParentNodes); RLPReader.RLPItem[] memory parentNodes = RLPReader.toList(item); bytes memory currentNode; RLPReader.RLPItem[] memory currentNodeList; bytes32 nodeKey = root; uint256 pathPtr = 0; bytes memory path = _getNibbleArray(encodedPath); if (path.length == 0) { return false; } for (uint256 i = 0; i < parentNodes.length; i++) { if (pathPtr > path.length) { return false; } currentNode = RLPReader.toRlpBytes(parentNodes[i]); if (nodeKey != keccak256(currentNode)) { return false; } currentNodeList = RLPReader.toList(parentNodes[i]); if (currentNodeList.length == 17) { if (pathPtr == path.length) { if (keccak256(RLPReader.toBytes(currentNodeList[16])) == keccak256(value)) { return true; } else { return false; } } uint8 nextPathNibble = uint8(path[pathPtr]); if (nextPathNibble > 16) { return false; } nodeKey = bytes32(RLPReader.toUintStrict(currentNodeList[nextPathNibble])); pathPtr += 1; } else if (currentNodeList.length == 2) { uint256 traversed = _nibblesToTraverse(RLPReader.toBytes(currentNodeList[0]), path, pathPtr); if (pathPtr + traversed == path.length) { //leaf node if (keccak256(RLPReader.toBytes(currentNodeList[1])) == keccak256(value)) { return true; } else { return false; } } //extension node if (traversed == 0) { return false; } pathPtr += traversed; nodeKey = bytes32(RLPReader.toUintStrict(currentNodeList[1])); } else { return false; } } } function _nibblesToTraverse( bytes memory encodedPartialPath, bytes memory path, uint256 pathPtr ) private pure returns (uint256) { uint256 len = 0; // encodedPartialPath has elements that are each two hex characters (1 byte), but partialPath // and slicedPath have elements that are each one hex character (1 nibble) bytes memory partialPath = _getNibbleArray(encodedPartialPath); bytes memory slicedPath = new bytes(partialPath.length); // pathPtr counts nibbles in path // partialPath.length is a number of nibbles for (uint256 i = pathPtr; i < pathPtr + partialPath.length; i++) { bytes1 pathNibble = path[i]; slicedPath[i - pathPtr] = pathNibble; } if (keccak256(partialPath) == keccak256(slicedPath)) { len = partialPath.length; } else { len = 0; } return len; } // bytes b must be hp encoded function _getNibbleArray(bytes memory b) internal pure returns (bytes memory) { bytes memory nibbles = ""; if (b.length > 0) { uint8 offset; uint8 hpNibble = uint8(_getNthNibbleOfBytes(0, b)); if (hpNibble == 1 || hpNibble == 3) { nibbles = new bytes(b.length * 2 - 1); bytes1 oddNibble = _getNthNibbleOfBytes(1, b); nibbles[0] = oddNibble; offset = 1; } else { nibbles = new bytes(b.length * 2 - 2); offset = 0; } for (uint256 i = offset; i < nibbles.length; i++) { nibbles[i] = _getNthNibbleOfBytes(i - offset + 2, b); } } return nibbles; } function _getNthNibbleOfBytes(uint256 n, bytes memory str) private pure returns (bytes1) { return bytes1(n % 2 == 0 ? uint8(str[n / 2]) / 0x10 : uint8(str[n / 2]) % 0x10); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library Merkle { function checkMembership( bytes32 leaf, uint256 index, bytes32 rootHash, bytes memory proof ) internal pure returns (bool) { require(proof.length % 32 == 0, "Invalid proof length"); uint256 proofHeight = proof.length / 32; // Proof of size n means, height of the tree is n+1. // In a tree of height n+1, max #leafs possible is 2 ^ n require(index < 2**proofHeight, "Leaf index is too big"); bytes32 proofElement; bytes32 computedHash = leaf; for (uint256 i = 32; i <= proof.length; i += 32) { assembly { proofElement := mload(add(proof, i)) } if (index % 2 == 0) { computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); } else { computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); } index = index / 2; } return computedHash == rootHash; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {RLPReader} from "./RLPReader.sol"; library ExitPayloadReader { using RLPReader for bytes; using RLPReader for RLPReader.RLPItem; uint8 constant WORD_SIZE = 32; struct ExitPayload { RLPReader.RLPItem[] data; } struct Receipt { RLPReader.RLPItem[] data; bytes raw; uint256 logIndex; } struct Log { RLPReader.RLPItem data; RLPReader.RLPItem[] list; } struct LogTopics { RLPReader.RLPItem[] data; } // copy paste of private copy() from RLPReader to avoid changing of existing contracts function copy( uint256 src, uint256 dest, uint256 len ) private pure { if (len == 0) return; // copy as many word sizes as possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } src += WORD_SIZE; dest += WORD_SIZE; } if (len == 0) return; // left over bytes. Mask is used to remove unwanted bytes from the word uint256 mask = 256**(WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) // zero out src let destpart := and(mload(dest), mask) // retrieve the bytes mstore(dest, or(destpart, srcpart)) } } function toExitPayload(bytes memory data) internal pure returns (ExitPayload memory) { RLPReader.RLPItem[] memory payloadData = data.toRlpItem().toList(); return ExitPayload(payloadData); } function getHeaderNumber(ExitPayload memory payload) internal pure returns (uint256) { return payload.data[0].toUint(); } function getBlockProof(ExitPayload memory payload) internal pure returns (bytes memory) { return payload.data[1].toBytes(); } function getBlockNumber(ExitPayload memory payload) internal pure returns (uint256) { return payload.data[2].toUint(); } function getBlockTime(ExitPayload memory payload) internal pure returns (uint256) { return payload.data[3].toUint(); } function getTxRoot(ExitPayload memory payload) internal pure returns (bytes32) { return bytes32(payload.data[4].toUint()); } function getReceiptRoot(ExitPayload memory payload) internal pure returns (bytes32) { return bytes32(payload.data[5].toUint()); } function getReceipt(ExitPayload memory payload) internal pure returns (Receipt memory receipt) { receipt.raw = payload.data[6].toBytes(); RLPReader.RLPItem memory receiptItem = receipt.raw.toRlpItem(); if (receiptItem.isList()) { // legacy tx receipt.data = receiptItem.toList(); } else { // pop first byte before parsting receipt bytes memory typedBytes = receipt.raw; bytes memory result = new bytes(typedBytes.length - 1); uint256 srcPtr; uint256 destPtr; assembly { srcPtr := add(33, typedBytes) destPtr := add(0x20, result) } copy(srcPtr, destPtr, result.length); receipt.data = result.toRlpItem().toList(); } receipt.logIndex = getReceiptLogIndex(payload); return receipt; } function getReceiptProof(ExitPayload memory payload) internal pure returns (bytes memory) { return payload.data[7].toBytes(); } function getBranchMaskAsBytes(ExitPayload memory payload) internal pure returns (bytes memory) { return payload.data[8].toBytes(); } function getBranchMaskAsUint(ExitPayload memory payload) internal pure returns (uint256) { return payload.data[8].toUint(); } function getReceiptLogIndex(ExitPayload memory payload) internal pure returns (uint256) { return payload.data[9].toUint(); } // Receipt methods function toBytes(Receipt memory receipt) internal pure returns (bytes memory) { return receipt.raw; } function getLog(Receipt memory receipt) internal pure returns (Log memory) { RLPReader.RLPItem memory logData = receipt.data[3].toList()[receipt.logIndex]; return Log(logData, logData.toList()); } // Log methods function getEmitter(Log memory log) internal pure returns (address) { return RLPReader.toAddress(log.list[0]); } function getTopics(Log memory log) internal pure returns (LogTopics memory) { return LogTopics(log.list[1].toList()); } function getData(Log memory log) internal pure returns (bytes memory) { return log.list[2].toBytes(); } function toRlpBytes(Log memory log) internal pure returns (bytes memory) { return log.data.toRlpBytes(); } // LogTopics methods function getField(LogTopics memory topics, uint256 index) internal pure returns (RLPReader.RLPItem memory) { return topics.data[index]; } }
{ "optimizer": { "enabled": false, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_checkpointManager","type":"address"},{"internalType":"address","name":"_fxRoot","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"AlreadyBound","type":"error"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"BondsDisabled","type":"error"},{"inputs":[],"name":"InvalidQueryRange","type":"error"},{"inputs":[],"name":"MaxSupplyReached","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"NoContractsAllowed","type":"error"},{"inputs":[],"name":"NotAnOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"NotBound","type":"error"},{"inputs":[],"name":"NotContractOwner","type":"error"},{"inputs":[],"name":"NotSalesContract","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"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":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"cmd","type":"string"},{"indexed":false,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"RequestSend","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":[],"name":"BOUND","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEND_MESSAGE_EVENT_SIG","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNBOUND","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","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":[],"name":"bondsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"bound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"checkpointManager","outputs":[{"internalType":"contract ICheckpointManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"explicitOwnershipOf","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"startTimestamp","type":"uint64"},{"internalType":"bool","name":"burned","type":"bool"},{"internalType":"uint24","name":"extraData","type":"uint24"}],"internalType":"struct IERC721A.TokenOwnership","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"explicitOwnershipsOf","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"startTimestamp","type":"uint64"},{"internalType":"bool","name":"burned","type":"bool"},{"internalType":"uint24","name":"extraData","type":"uint24"}],"internalType":"struct IERC721A.TokenOwnership[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fxChildTunnel","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fxRoot","outputs":[{"internalType":"contract IFxStateSender","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"processedExits","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"inputData","type":"bytes"}],"name":"receiveMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","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":"tokenId","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":"string","name":"URI","type":"string"}],"name":"setBaseTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"status","type":"bool"}],"name":"setBondsEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_fxChildTunnel","type":"address"}],"name":"setFxChildTunnel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_salesContractAddress","type":"address"}],"name":"setSalesContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenIdToBound","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"stop","type":"uint256"}],"name":"tokensOfOwnerIn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","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":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"unbound","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620064a2380380620064a283398181016040528101906200003791906200040b565b8383838381600290805190602001906200005392919062000159565b5080600390805190602001906200006c92919062000159565b506200007d6200015460201b60201c565b600081905550505033600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050505062000520565b600090565b8280546200016790620004ea565b90600052602060002090601f0160209004810192826200018b5760008555620001d7565b82601f10620001a657805160ff1916838001178555620001d7565b82800160010185558215620001d7579182015b82811115620001d6578251825591602001919060010190620001b9565b5b509050620001e69190620001ea565b5090565b5b8082111562000205576000816000905550600101620001eb565b5090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200024a826200021d565b9050919050565b6200025c816200023d565b81146200026857600080fd5b50565b6000815190506200027c8162000251565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620002d7826200028c565b810181811067ffffffffffffffff82111715620002f957620002f86200029d565b5b80604052505050565b60006200030e62000209565b90506200031c8282620002cc565b919050565b600067ffffffffffffffff8211156200033f576200033e6200029d565b5b6200034a826200028c565b9050602081019050919050565b60005b83811015620003775780820151818401526020810190506200035a565b8381111562000387576000848401525b50505050565b6000620003a46200039e8462000321565b62000302565b905082815260208101848484011115620003c357620003c262000287565b5b620003d084828562000357565b509392505050565b600082601f830112620003f057620003ef62000282565b5b8151620004028482602086016200038d565b91505092915050565b6000806000806080858703121562000428576200042762000213565b5b600062000438878288016200026b565b94505060206200044b878288016200026b565b935050604085015167ffffffffffffffff8111156200046f576200046e62000218565b5b6200047d87828801620003d8565b925050606085015167ffffffffffffffff811115620004a157620004a062000218565b5b620004af87828801620003d8565b91505092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200050357607f821691505b602082108114156200051a5762000519620004bb565b5b50919050565b615f7280620005306000396000f3fe608060405234801561001057600080fd5b50600436106102275760003560e01c80638da5cb5b11610130578063b88d4fde116100b8578063ccea458f1161007c578063ccea458f1461069a578063de9b771f146106b8578063e985e9c5146106d6578063f2fde38b14610706578063f953cec71461072257610227565b8063b88d4fde146105e2578063c0857ba0146105fe578063c23dc68f1461061c578063c52141911461064c578063c87b56dd1461066a57610227565b806399a2557a116100ff57806399a2557a146105425780639b5719a614610572578063a22cb4651461058e578063aa22b45c146105aa578063aea4e49e146105c657610227565b80638da5cb5b146104b85780639094adb3146104d657806395d89b4114610506578063972c49281461052457610227565b806340c10f19116101b35780636352211e116101825780636352211e146103f057806370734dcf1461042057806370a082311461043c5780637bef587c1461046c5780638462151c1461048857610227565b806340c10f191461035857806342842e0e146103745780635bbb217714610390578063607f2d42146103c057610227565b80630e387de6116101fa5780630e387de6146102c657806318160ddd146102e45780631edc2e721461030257806323b872dd1461032057806330176e131461033c57610227565b806301ffc9a71461022c57806306fdde031461025c578063081812fc1461027a578063095ea7b3146102aa575b600080fd5b61024660048036038101906102419190614541565b61073e565b6040516102539190614589565b60405180910390f35b6102646107d0565b604051610271919061463d565b60405180910390f35b610294600480360381019061028f9190614695565b610862565b6040516102a19190614703565b60405180910390f35b6102c460048036038101906102bf919061474a565b6108e1565b005b6102ce610a25565b6040516102db91906147a3565b60405180910390f35b6102ec610a4c565b6040516102f991906147cd565b60405180910390f35b61030a610a63565b6040516103179190614589565b60405180910390f35b61033a600480360381019061033591906147e8565b610a76565b005b610356600480360381019061035191906148a0565b610d9b565b005b610372600480360381019061036d919061474a565b610e38565b005b61038e600480360381019061038991906147e8565b610f1b565b005b6103aa60048036038101906103a59190614943565b610f3b565b6040516103b79190614af3565b60405180910390f35b6103da60048036038101906103d59190614b41565b610ffe565b6040516103e79190614589565b60405180910390f35b61040a60048036038101906104059190614695565b61101e565b6040516104179190614703565b60405180910390f35b61043a60048036038101906104359190614943565b611030565b005b61045660048036038101906104519190614b6e565b6112ea565b60405161046391906147cd565b60405180910390f35b61048660048036038101906104819190614943565b6113a3565b005b6104a2600480360381019061049d9190614b6e565b61169c565b6040516104af9190614c59565b60405180910390f35b6104c06117e6565b6040516104cd9190614703565b60405180910390f35b6104f060048036038101906104eb9190614695565b61180c565b6040516104fd9190614589565b60405180910390f35b61050e61182c565b60405161051b919061463d565b60405180910390f35b61052c6118be565b6040516105399190614703565b60405180910390f35b61055c60048036038101906105579190614c7b565b6118e4565b6040516105699190614c59565b60405180910390f35b61058c60048036038101906105879190614b6e565b611af8565b005b6105a860048036038101906105a39190614cfa565b611bc3565b005b6105c460048036038101906105bf9190614d3a565b611cce565b005b6105e060048036038101906105db9190614b6e565b611d72565b005b6105fc60048036038101906105f79190614e97565b611e3d565b005b610606611eb0565b6040516106139190614f79565b60405180910390f35b61063660048036038101906106319190614695565b611ed6565b6040516106439190614fe9565b60405180910390f35b610654611f40565b60405161066191906147a3565b60405180910390f35b610684600480360381019061067f9190614695565b611f64565b604051610691919061463d565b60405180910390f35b6106a2612003565b6040516106af91906147a3565b60405180910390f35b6106c0612027565b6040516106cd9190615025565b60405180910390f35b6106f060048036038101906106eb9190615040565b61204d565b6040516106fd9190614589565b60405180910390f35b610720600480360381019061071b9190614b6e565b6120e1565b005b61073c60048036038101906107379190615080565b6121ac565b005b60006301ffc9a760e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061079957506380ac58cd60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806107c95750635b5e139f60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6060600280546107df906150f8565b80601f016020809104026020016040519081016040528092919081815260200182805461080b906150f8565b80156108585780601f1061082d57610100808354040283529160200191610858565b820191906000526020600020905b81548152906001019060200180831161083b57829003601f168201915b5050505050905090565b600061086d826121c6565b6108a3576040517fcf4700e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60006108ec8261101e565b90508073ffffffffffffffffffffffffffffffffffffffff1661090d612225565b73ffffffffffffffffffffffffffffffffffffffff16146109705761093981610934612225565b61204d565b61096f576040517fcfb3b94200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b826006600084815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b7f8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b03660001b81565b6000610a5661222d565b6001546000540303905090565b600f60009054906101000a900460ff1681565b6000610a8182612232565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610ae8576040517fa114810000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080610af484612300565b91509150610b0a8187610b05612225565b612327565b610b5657610b1f86610b1a612225565b61204d565b610b55576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161415610bbd576040517fea553b3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bca868686600161236b565b8015610bd557600082555b600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081546001900391905081905550600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815460010191905081905550610ca385610c7f8888876124de565b7c020000000000000000000000000000000000000000000000000000000017612506565b600460008681526020019081526020016000208190555060007c020000000000000000000000000000000000000000000000000000000084161415610d2b576000600185019050600060046000838152602001908152602001600020541415610d29576000548114610d28578360046000838152602001908152602001600020819055505b5b505b838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4610d938686866001612531565b505050505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610e22576040517fbfcafd3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8181600e9190610e33929190614362565b505050565b600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ebf576040517ff90715e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115b481610ecb612537565b610ed59190615159565b1115610f0d576040517fd05cb60900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f17828261254a565b5050565b610f3683838360405180602001604052806000815250611e3d565b505050565b6060600083839050905060008167ffffffffffffffff811115610f6157610f60614d6c565b5b604051908082528060200260200182016040528015610f9a57816020015b610f876143e8565b815260200190600190039081610f7f5790505b50905060005b828114610ff257610fc9868683818110610fbd57610fbc6151af565b5b90506020020135611ed6565b828281518110610fdc57610fdb6151af565b5b6020026020010181905250806001019050610fa0565b50809250505092915050565b600c6020528060005260406000206000915054906101000a900460ff1681565b600061102982612232565b9050919050565b600080339050803b91503273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580611076575060008214155b156110ad576040517f5a156d6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b84849050811015611235573373ffffffffffffffffffffffffffffffffffffffff166110f48686848181106110e8576110e76151af565b5b9050602002013561101e565b73ffffffffffffffffffffffffffffffffffffffff1614611141576040517feea91ff800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600015156010600087878581811061115c5761115b6151af565b5b90506020020135815260200190815260200160002060009054906101000a900460ff16151514156111dd5784848281811061119a576111996151af565b5b905060200201356040517fd0078a0a0000000000000000000000000000000000000000000000000000000081526004016111d491906147cd565b60405180910390fd5b6000601060008787858181106111f6576111f56151af565b5b90506020020135815260200190815260200160002060006101000a81548160ff021916908315150217905550808061122d906151de565b9150506110b0565b5060007f46ea84878955907861000722f4dd80a932935b7b3669b3a736e54d8ed9dca5c633868660405160200161126e93929190615288565b60405160208183030381529060405260405160200161128e92919061530f565b60405160208183030381529060405290507f137b854e7e99f3421d5319954d65a2fb8cd25a72297f898f1e662f0843b727d53386866040516112d29392919061538b565b60405180910390a16112e381612707565b5050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611352576040517f8f4eb60400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054169050919050565b600f60009054906101000a900460ff166113e9576040517f78d9002800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080339050803b91503273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158061142f575060008214155b15611466576040517f5a156d6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b848490508110156115e7573373ffffffffffffffffffffffffffffffffffffffff166114ad8686848181106114a1576114a06151af565b5b9050602002013561101e565b73ffffffffffffffffffffffffffffffffffffffff16146114fa576040517feea91ff800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60106000868684818110611511576115106151af565b5b90506020020135815260200190815260200160002060009054906101000a900460ff161561158f5784848281811061154c5761154b6151af565b5b905060200201356040517f3de74d5b00000000000000000000000000000000000000000000000000000000815260040161158691906147cd565b60405180910390fd5b6001601060008787858181106115a8576115a76151af565b5b90506020020135815260200190815260200160002060006101000a81548160ff02191690831515021790555080806115df906151de565b915050611469565b5060007f49a368f7e595a507e0eaa27f07cfde74ff475d8dafcdf3829d5d9b4a75f28a8433868660405160200161162093929190615288565b60405160208183030381529060405260405160200161164092919061530f565b60405160208183030381529060405290507f137b854e7e99f3421d5319954d65a2fb8cd25a72297f898f1e662f0843b727d53386866040516116849392919061541c565b60405180910390a161169581612707565b5050505050565b606060008060006116ac856112ea565b905060008167ffffffffffffffff8111156116ca576116c9614d6c565b5b6040519080825280602002602001820160405280156116f85781602001602082028036833780820191505090505b5090506117036143e8565b600061170d61222d565b90505b8386146117d857611720816127bb565b9150816040015115611731576117cd565b600073ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff161461177157816000015194505b8773ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614156117cc57808387806001019850815181106117bf576117be6151af565b5b6020026020010181815250505b5b806001019050611710565b508195505050505050919050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60106020528060005260406000206000915054906101000a900460ff1681565b60606003805461183b906150f8565b80601f0160208091040260200160405190810160405280929190818152602001828054611867906150f8565b80156118b45780601f10611889576101008083540402835291602001916118b4565b820191906000526020600020905b81548152906001019060200180831161189757829003601f168201915b5050505050905090565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606081831061191f576040517f32c1995a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061192a6127e6565b905061193461222d565b8510156119465761194361222d565b94505b80841115611952578093505b600061195d876112ea565b90508486101561198057600086860390508181101561197a578091505b50611985565b600090505b60008167ffffffffffffffff8111156119a1576119a0614d6c565b5b6040519080825280602002602001820160405280156119cf5781602001602082028036833780820191505090505b50905060008214156119e75780945050505050611af1565b60006119f288611ed6565b905060008160400151611a0757816000015190505b60008990505b888114158015611a1d5750848714155b15611ae357611a2b816127bb565b9250826040015115611a3c57611ad8565b600073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff1614611a7c57826000015191505b8a73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611ad75780848880600101995081518110611aca57611ac96151af565b5b6020026020010181815250505b5b806001019050611a0d565b508583528296505050505050505b9392505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611b7f576040517fbfcafd3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b8060076000611bd0612225565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16611c7d612225565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611cc29190614589565b60405180910390a35050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611d55576040517fbfcafd3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600f60006101000a81548160ff02191690831515021790555050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611df9576040517fbfcafd3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600b60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b611e48848484610a76565b60008373ffffffffffffffffffffffffffffffffffffffff163b14611eaa57611e73848484846127ef565b611ea9576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b50505050565b600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b611ede6143e8565b611ee66143e8565b611eee61222d565b831080611f025750611efe6127e6565b8310155b15611f105780915050611f3b565b611f19836127bb565b9050806040015115611f2e5780915050611f3b565b611f3783612940565b9150505b919050565b7f49a368f7e595a507e0eaa27f07cfde74ff475d8dafcdf3829d5d9b4a75f28a8481565b6060611f6f826121c6565b611fa5576040517fa14c4b5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611faf612960565b9050600081511415611fd05760405180602001604052806000815250611ffb565b80611fda846129f2565b604051602001611feb92919061549d565b6040516020818303038152906040525b915050919050565b7f46ea84878955907861000722f4dd80a932935b7b3669b3a736e54d8ed9dca5c681565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612168576040517fbfcafd3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006121b782612a42565b90506121c281612d47565b5050565b6000816121d161222d565b111580156121e0575060005482105b801561221e575060007c0100000000000000000000000000000000000000000000000000000000600460008581526020019081526020016000205416145b9050919050565b600033905090565b600090565b6000808290508061224161222d565b116122c9576000548110156122c85760006004600083815260200190815260200160002054905060007c0100000000000000000000000000000000000000000000000000000000821614156122c6575b60008114156122bc576004600083600190039350838152602001908152602001600020549050612291565b80925050506122fb565b505b5b6040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b60008060006006600085815260200190815260200160002090508092508254915050915091565b600073ffffffffffffffffffffffffffffffffffffffff8316925073ffffffffffffffffffffffffffffffffffffffff821691508382148383141790509392505050565b6010600083815260200190815260200160002060009054906101000a900460ff16156124d85760006010600084815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600167ffffffffffffffff8111156123da576123d9614d6c565b5b6040519080825280602002602001820160405280156124085781602001602082028036833780820191505090505b50905082816000815181106124205761241f6151af565b5b60200260200101818152505060007f46ea84878955907861000722f4dd80a932935b7b3669b3a736e54d8ed9dca5c686836040516020016124629291906154c1565b60405160208183030381529060405260405160200161248292919061530f565b60405160208183030381529060405290507f137b854e7e99f3421d5319954d65a2fb8cd25a72297f898f1e662f0843b727d586836040516124c49291906154f1565b60405180910390a16124d581612707565b50505b50505050565b60008060e883901c905060e86124f5868684612d4a565b62ffffff16901b9150509392505050565b600073ffffffffffffffffffffffffffffffffffffffff83169250814260a01b178317905092915050565b50505050565b600061254161222d565b60005403905090565b600080549050600082141561258b576040517fb562e8dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612598600084838561236b565b600160406001901b178202600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555061260f8361260060008660006124de565b61260985612d53565b17612506565b6004600083815260200190815260200160002081905550600080838301905073ffffffffffffffffffffffffffffffffffffffff85169150828260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600183015b8181146126b057808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600181019050612675565b5060008214156126ec576040517f2e07630000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060008190555050506127026000848385612531565b505050565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b4720477600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401612786929190615534565b600060405180830381600087803b1580156127a057600080fd5b505af11580156127b4573d6000803e3d6000fd5b5050505050565b6127c36143e8565b6127df6004600084815260200190815260200160002054612d63565b9050919050565b60008054905090565b60008373ffffffffffffffffffffffffffffffffffffffff1663150b7a02612815612225565b8786866040518563ffffffff1660e01b81526004016128379493929190615564565b6020604051808303816000875af192505050801561287357506040513d601f19601f8201168201806040525081019061287091906155c5565b60015b6128ed573d80600081146128a3576040519150601f19603f3d011682016040523d82523d6000602084013e6128a8565b606091505b506000815114156128e5576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050949350505050565b6129486143e8565b61295961295483612232565b612d63565b9050919050565b6060600e805461296f906150f8565b80601f016020809104026020016040519081016040528092919081815260200182805461299b906150f8565b80156129e85780601f106129bd576101008083540402835291602001916129e8565b820191906000526020600020905b8154815290600101906020018083116129cb57829003601f168201915b5050505050905090565b606060806040510190508060405280825b600115612a2e57600183039250600a81066030018353600a8104905080612a2957612a2e565b612a03565b508181036020830392508083525050919050565b60606000612a4f83612e19565b90506000612a5c82612e4d565b90506000612a6983612e7e565b9050600081612a7784612eaf565b612a80866130c5565b604051602001612a929392919061564f565b60405160208183030381529060405280519060200120905060001515600c600083815260200190815260200160002060009054906101000a900460ff16151514612b11576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b08906156fa565b60405180910390fd5b6001600c600083815260200190815260200160002060006101000a81548160ff0219169083151502179055506000612b48856130f6565b90506000612b558261321b565b9050612b6081613292565b73ffffffffffffffffffffffffffffffffffffffff16600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612bef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612be69061578c565b60405180910390fd5b6000612bfa876132c3565b9050612c18612c08846132f7565b87612c128a613305565b84613336565b612c57576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c4e9061581e565b60405180910390fd5b612c8585612c648961363c565b612c6d8a61366d565b84612c778c6136a1565b612c808d6136d2565b613703565b506000612c918361384a565b90507f8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b03660001b612cd3612cce60008461388f90919063ffffffff16565b6138be565b60001b14612d16576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d0d9061588a565b60405180910390fd5b6000612d2184613941565b806020019051810190612d34919061591a565b9050809950505050505050505050919050565b50565b60009392505050565b60006001821460e11b9050919050565b612d6b6143e8565b81816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060a082901c816020019067ffffffffffffffff16908167ffffffffffffffff168152505060007c01000000000000000000000000000000000000000000000000000000008316141581604001901515908115158152505060e882901c816060019062ffffff16908162ffffff1681525050919050565b612e21614437565b6000612e34612e2f84613972565b6139a0565b9050604051806020016040528082815250915050919050565b6060612e778260000151600881518110612e6a57612e696151af565b5b6020026020010151613ab5565b9050919050565b6000612ea88260000151600281518110612e9b57612e9a6151af565b5b60200260200101516138be565b9050919050565b606060006040518060200160405280600081525090506000835111156130bc57600080612edd600086613b6c565b60f81c905060018160ff161480612ef7575060038160ff16145b15612fc157600160028651612f0c9190615963565b612f1691906159bd565b67ffffffffffffffff811115612f2f57612f2e614d6c565b5b6040519080825280601f01601f191660200182016040528015612f615781602001600182028036833780820191505090505b5092506000612f71600187613b6c565b90508084600081518110612f8857612f876151af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600192505061302d565b6002808651612fd09190615963565b612fda91906159bd565b67ffffffffffffffff811115612ff357612ff2614d6c565b5b6040519080825280601f01601f1916602001820160405280156130255781602001600182028036833780820191505090505b509250600091505b60008260ff1690505b83518110156130b85761306360028460ff168361305391906159bd565b61305d9190615159565b87613b6c565b848281518110613076576130756151af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080806130b0906151de565b915050613036565b5050505b80915050919050565b60006130ef82600001516009815181106130e2576130e16151af565b5b60200260200101516138be565b9050919050565b6130fe61444a565b6131268260000151600681518110613119576131186151af565b5b6020026020010151613ab5565b8160200181905250600061313d8260200151613972565b905061314881613c04565b1561316357613156816139a0565b8260000181905250613203565b60008260200151905060006001825161317c91906159bd565b67ffffffffffffffff81111561319557613194614d6c565b5b6040519080825280601f01601f1916602001820160405280156131c75781602001600182028036833780820191505090505b5090506000808360210191508260200190506131e582828551613c52565b6131f66131f184613972565b6139a0565b8660000181905250505050505b61320c836130c5565b82604001818152505050919050565b61322361446b565b600061324d83600001516003815181106132405761323f6151af565b5b60200260200101516139a0565b836040015181518110613263576132626151af565b5b602002602001015190506040518060400160405280828152602001613287836139a0565b815250915050919050565b60006132bc82602001516000815181106132af576132ae6151af565b5b6020026020010151613cfd565b9050919050565b60006132ed82600001516005815181106132e0576132df6151af565b5b60200260200101516138be565b60001b9050919050565b606081602001519050919050565b606061332f8260000151600781518110613322576133216151af565b5b6020026020010151613ab5565b9050919050565b60008061334284613972565b9050600061334f826139a0565b905060608060008690506000806133658b612eaf565b9050600081511415613381576000975050505050505050613634565b60005b865181101561362b5781518311156133a757600098505050505050505050613634565b6133ca8782815181106133bd576133bc6151af565b5b6020026020010151613d20565b9550858051906020012084146133eb57600098505050505050505050613634565b61340e878281518110613401576134006151af565b5b60200260200101516139a0565b945060118551141561350157815183141561347e578c8051906020012061344f86601081518110613442576134416151af565b5b6020026020010151613ab5565b80519060200120141561346d57600198505050505050505050613634565b600098505050505050505050613634565b6000828481518110613493576134926151af565b5b602001015160f81c60f81b60f81c905060108160ff1611156134c15760009950505050505050505050613634565b6134e7868260ff16815181106134da576134d96151af565b5b6020026020010151613db0565b60001b94506001846134f99190615159565b935050613618565b60028551141561360657600061353b61353487600081518110613527576135266151af565b5b6020026020010151613ab5565b8486613de7565b90508251818561354b9190615159565b14156135ae578d8051906020012061357d876001815181106135705761356f6151af565b5b6020026020010151613ab5565b80519060200120141561359c5760019950505050505050505050613634565b60009950505050505050505050613634565b60008114156135c95760009950505050505050505050613634565b80846135d59190615159565b93506135fb866001815181106135ee576135ed6151af565b5b6020026020010151613db0565b60001b945050613617565b600098505050505050505050613634565b5b8080613623906151de565b915050613384565b50505050505050505b949350505050565b60006136668260000151600381518110613659576136586151af565b5b60200260200101516138be565b9050919050565b6000613697826000015160048151811061368a576136896151af565b5b60200260200101516138be565b60001b9050919050565b60006136cb82600001516000815181106136be576136bd6151af565b5b60200260200101516138be565b9050919050565b60606136fc82600001516001815181106136ef576136ee6151af565b5b6020026020010151613ab5565b9050919050565b600080600080600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166341539d4a876040518263ffffffff1660e01b815260040161376491906147cd565b60a060405180830381865afa158015613781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a59190615a30565b50935050925092506137fb828b6137bc91906159bd565b84878d8d8d8d6040516020016137d59493929190615acc565b60405160208183030381529060405280519060200120613f1d909392919063ffffffff16565b61383a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161383190615b66565b60405180910390fd5b8093505050509695505050505050565b61385261448b565b60405180602001604052806138858460200151600181518110613878576138776151af565b5b60200260200101516139a0565b8152509050919050565b61389761449e565b826000015182815181106138ae576138ad6151af565b5b6020026020010151905092915050565b60008082600001511180156138d857506021826000015111155b6138e157600080fd5b60006138f0836020015161408e565b9050600081846000015161390491906159bd565b90506000808386602001516139199190615159565b905080519150602083101561393557826020036101000a820491505b81945050505050919050565b606061396b826020015160028151811061395e5761395d6151af565b5b6020026020010151613ab5565b9050919050565b61397a61449e565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606139ab82613c04565b6139b457600080fd5b60006139bf8361414d565b905060008167ffffffffffffffff8111156139dd576139dc614d6c565b5b604051908082528060200260200182016040528015613a1657816020015b613a0361449e565b8152602001906001900390816139fb5790505b5090506000613a28856020015161408e565b8560200151613a379190615159565b9050600080600090505b84811015613aa857613a52836141db565b9150604051806040016040528083815260200184815250848281518110613a7c57613a7b6151af565b5b60200260200101819052508183613a939190615159565b92508080613aa0906151de565b915050613a41565b5082945050505050919050565b60606000826000015111613ac857600080fd5b6000613ad7836020015161408e565b90506000818460000151613aeb91906159bd565b905060008167ffffffffffffffff811115613b0957613b08614d6c565b5b6040519080825280601f01601f191660200182016040528015613b3b5781602001600182028036833780820191505090505b5090506000816020019050613b60848760200151613b599190615159565b82856142b7565b81945050505050919050565b600080600284613b7c9190615bb5565b14613bbf57601082600285613b919190615be6565b81518110613ba257613ba16151af565b5b602001015160f81c60f81b60f81c613bba9190615c24565b613bf9565b601082600285613bcf9190615be6565b81518110613be057613bdf6151af565b5b602001015160f81c60f81b60f81c613bf89190615c55565b5b60f81b905092915050565b60008082600001511415613c1b5760009050613c4d565b60008083602001519050805160001a915060c060ff168260ff161015613c4657600092505050613c4d565b6001925050505b919050565b6000811415613c6057613cf8565b5b602060ff168110613cab5782518252602060ff1683613c809190615159565b9250602060ff1682613c929190615159565b9150602060ff1681613ca491906159bd565b9050613c61565b6000811415613cb957613cf8565b6000600182602060ff16613ccd91906159bd565b610100613cda9190615db9565b613ce491906159bd565b905080198451168184511681811785525050505b505050565b60006015826000015114613d1057600080fd5b613d19826138be565b9050919050565b60606000826000015167ffffffffffffffff811115613d4257613d41614d6c565b5b6040519080825280601f01601f191660200182016040528015613d745781602001600182028036833780820191505090505b509050600081511415613d8a5780915050613dab565b6000816020019050613da584602001518286600001516142b7565b81925050505b919050565b60006021826000015114613dc357600080fd5b60008060018460200151613dd79190615159565b9050805191508192505050919050565b600080600090506000613df986612eaf565b90506000815167ffffffffffffffff811115613e1857613e17614d6c565b5b6040519080825280601f01601f191660200182016040528015613e4a5781602001600182028036833780820191505090505b50905060008590505b825186613e609190615159565b811015613eeb576000878281518110613e7c57613e7b6151af565b5b602001015160f81c60f81b905080838884613e9791906159bd565b81518110613ea857613ea76151af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350508080613ee3906151de565b915050613e53565b50808051906020012082805190602001201415613f0b5781519250613f10565b600092505b8293505050509392505050565b60008060208351613f2e9190615bb5565b14613f6e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613f6590615e50565b60405180910390fd5b600060208351613f7e9190615be6565b9050806002613f8d9190615db9565b8510613fce576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613fc590615ebc565b60405180910390fd5b6000808790506000602090505b8551811161407d578086015192506000600289613ff89190615bb5565b141561402e578183604051602001614011929190615edc565b60405160208183030381529060405280519060200120915061405a565b8282604051602001614041929190615edc565b6040516020818303038152906040528051906020012091505b6002886140679190615be6565b97506020816140769190615159565b9050613fdb565b508581149350505050949350505050565b600080825160001a9050608060ff168110156140ae576000915050614148565b60b860ff168110806140d3575060c060ff1681101580156140d2575060f860ff1681105b5b156140e2576001915050614148565b60c060ff1681101561411d5760018060b86140fd9190615f08565b60ff168261410b91906159bd565b6141159190615159565b915050614148565b60018060f861412c9190615f08565b60ff168261413a91906159bd565b6141449190615159565b9150505b919050565b6000808260000151141561416457600090506141d6565b600080614174846020015161408e565b84602001516141839190615159565b905060008460000151856020015161419b9190615159565b90505b808210156141cf576141af826141db565b826141ba9190615159565b915082806141c7906151de565b93505061419e565b8293505050505b919050565b6000806000835160001a9050608060ff168110156141fc57600191506142ad565b60b860ff1681101561422b576001608060ff168261421a91906159bd565b6142249190615159565b91506142ac565b60c060ff1681101561425b5760b78103600185019450806020036101000a855104600182018101935050506142ab565b60f860ff1681101561428a57600160c060ff168261427991906159bd565b6142839190615159565b91506142aa565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156142c55761435d565b5b602060ff1681106143105782518252602060ff16836142e59190615159565b9250602060ff16826142f79190615159565b9150602060ff168161430991906159bd565b90506142c6565b600081141561431e5761435d565b6000600182602060ff1661433291906159bd565b61010061433f9190615db9565b61434991906159bd565b905080198451168184511681811785525050505b505050565b82805461436e906150f8565b90600052602060002090601f01602090048101928261439057600085556143d7565b82601f106143a957803560ff19168380011785556143d7565b828001600101855582156143d7579182015b828111156143d65782358255916020019190600101906143bb565b5b5090506143e491906144b8565b5090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600067ffffffffffffffff168152602001600015158152602001600062ffffff1681525090565b6040518060200160405280606081525090565b60405180606001604052806060815260200160608152602001600081525090565b604051806040016040528061447e61449e565b8152602001606081525090565b6040518060200160405280606081525090565b604051806040016040528060008152602001600081525090565b5b808211156144d15760008160009055506001016144b9565b5090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61451e816144e9565b811461452957600080fd5b50565b60008135905061453b81614515565b92915050565b600060208284031215614557576145566144df565b5b60006145658482850161452c565b91505092915050565b60008115159050919050565b6145838161456e565b82525050565b600060208201905061459e600083018461457a565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156145de5780820151818401526020810190506145c3565b838111156145ed576000848401525b50505050565b6000601f19601f8301169050919050565b600061460f826145a4565b61461981856145af565b93506146298185602086016145c0565b614632816145f3565b840191505092915050565b600060208201905081810360008301526146578184614604565b905092915050565b6000819050919050565b6146728161465f565b811461467d57600080fd5b50565b60008135905061468f81614669565b92915050565b6000602082840312156146ab576146aa6144df565b5b60006146b984828501614680565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006146ed826146c2565b9050919050565b6146fd816146e2565b82525050565b600060208201905061471860008301846146f4565b92915050565b614727816146e2565b811461473257600080fd5b50565b6000813590506147448161471e565b92915050565b60008060408385031215614761576147606144df565b5b600061476f85828601614735565b925050602061478085828601614680565b9150509250929050565b6000819050919050565b61479d8161478a565b82525050565b60006020820190506147b86000830184614794565b92915050565b6147c78161465f565b82525050565b60006020820190506147e260008301846147be565b92915050565b600080600060608486031215614801576148006144df565b5b600061480f86828701614735565b935050602061482086828701614735565b925050604061483186828701614680565b9150509250925092565b600080fd5b600080fd5b600080fd5b60008083601f8401126148605761485f61483b565b5b8235905067ffffffffffffffff81111561487d5761487c614840565b5b60208301915083600182028301111561489957614898614845565b5b9250929050565b600080602083850312156148b7576148b66144df565b5b600083013567ffffffffffffffff8111156148d5576148d46144e4565b5b6148e18582860161484a565b92509250509250929050565b60008083601f8401126149035761490261483b565b5b8235905067ffffffffffffffff8111156149205761491f614840565b5b60208301915083602082028301111561493c5761493b614845565b5b9250929050565b6000806020838503121561495a576149596144df565b5b600083013567ffffffffffffffff811115614978576149776144e4565b5b614984858286016148ed565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6149c5816146e2565b82525050565b600067ffffffffffffffff82169050919050565b6149e8816149cb565b82525050565b6149f78161456e565b82525050565b600062ffffff82169050919050565b614a15816149fd565b82525050565b608082016000820151614a3160008501826149bc565b506020820151614a4460208501826149df565b506040820151614a5760408501826149ee565b506060820151614a6a6060850182614a0c565b50505050565b6000614a7c8383614a1b565b60808301905092915050565b6000602082019050919050565b6000614aa082614990565b614aaa818561499b565b9350614ab5836149ac565b8060005b83811015614ae6578151614acd8882614a70565b9750614ad883614a88565b925050600181019050614ab9565b5085935050505092915050565b60006020820190508181036000830152614b0d8184614a95565b905092915050565b614b1e8161478a565b8114614b2957600080fd5b50565b600081359050614b3b81614b15565b92915050565b600060208284031215614b5757614b566144df565b5b6000614b6584828501614b2c565b91505092915050565b600060208284031215614b8457614b836144df565b5b6000614b9284828501614735565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b614bd08161465f565b82525050565b6000614be28383614bc7565b60208301905092915050565b6000602082019050919050565b6000614c0682614b9b565b614c108185614ba6565b9350614c1b83614bb7565b8060005b83811015614c4c578151614c338882614bd6565b9750614c3e83614bee565b925050600181019050614c1f565b5085935050505092915050565b60006020820190508181036000830152614c738184614bfb565b905092915050565b600080600060608486031215614c9457614c936144df565b5b6000614ca286828701614735565b9350506020614cb386828701614680565b9250506040614cc486828701614680565b9150509250925092565b614cd78161456e565b8114614ce257600080fd5b50565b600081359050614cf481614cce565b92915050565b60008060408385031215614d1157614d106144df565b5b6000614d1f85828601614735565b9250506020614d3085828601614ce5565b9150509250929050565b600060208284031215614d5057614d4f6144df565b5b6000614d5e84828501614ce5565b91505092915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b614da4826145f3565b810181811067ffffffffffffffff82111715614dc357614dc2614d6c565b5b80604052505050565b6000614dd66144d5565b9050614de28282614d9b565b919050565b600067ffffffffffffffff821115614e0257614e01614d6c565b5b614e0b826145f3565b9050602081019050919050565b82818337600083830152505050565b6000614e3a614e3584614de7565b614dcc565b905082815260208101848484011115614e5657614e55614d67565b5b614e61848285614e18565b509392505050565b600082601f830112614e7e57614e7d61483b565b5b8135614e8e848260208601614e27565b91505092915050565b60008060008060808587031215614eb157614eb06144df565b5b6000614ebf87828801614735565b9450506020614ed087828801614735565b9350506040614ee187828801614680565b925050606085013567ffffffffffffffff811115614f0257614f016144e4565b5b614f0e87828801614e69565b91505092959194509250565b6000819050919050565b6000614f3f614f3a614f35846146c2565b614f1a565b6146c2565b9050919050565b6000614f5182614f24565b9050919050565b6000614f6382614f46565b9050919050565b614f7381614f58565b82525050565b6000602082019050614f8e6000830184614f6a565b92915050565b608082016000820151614faa60008501826149bc565b506020820151614fbd60208501826149df565b506040820151614fd060408501826149ee565b506060820151614fe36060850182614a0c565b50505050565b6000608082019050614ffe6000830184614f94565b92915050565b600061500f82614f46565b9050919050565b61501f81615004565b82525050565b600060208201905061503a6000830184615016565b92915050565b60008060408385031215615057576150566144df565b5b600061506585828601614735565b925050602061507685828601614735565b9150509250929050565b600060208284031215615096576150956144df565b5b600082013567ffffffffffffffff8111156150b4576150b36144e4565b5b6150c084828501614e69565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061511057607f821691505b60208210811415615124576151236150c9565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006151648261465f565b915061516f8361465f565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156151a4576151a361512a565b5b828201905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006151e98261465f565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561521c5761521b61512a565b5b600182019050919050565b600080fd5b60006152388385614ba6565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561526b5761526a615227565b5b60208302925061527c838584614e18565b82840190509392505050565b600060408201905061529d60008301866146f4565b81810360208301526152b081848661522c565b9050949350505050565b600081519050919050565b600082825260208201905092915050565b60006152e1826152ba565b6152eb81856152c5565b93506152fb8185602086016145c0565b615304816145f3565b840191505092915050565b60006040820190506153246000830185614794565b818103602083015261533681846152d6565b90509392505050565b7f554e424f554e4400000000000000000000000000000000000000000000000000600082015250565b60006153756007836145af565b91506153808261533f565b602082019050919050565b600060608201905081810360008301526153a481615368565b90506153b360208301866146f4565b81810360408301526153c681848661522c565b9050949350505050565b7f424f554e44000000000000000000000000000000000000000000000000000000600082015250565b60006154066005836145af565b9150615411826153d0565b602082019050919050565b60006060820190508181036000830152615435816153f9565b905061544460208301866146f4565b818103604083015261545781848661522c565b9050949350505050565b600081905092915050565b6000615477826145a4565b6154818185615461565b93506154918185602086016145c0565b80840191505092915050565b60006154a9828561546c565b91506154b5828461546c565b91508190509392505050565b60006040820190506154d660008301856146f4565b81810360208301526154e88184614bfb565b90509392505050565b6000606082019050818103600083015261550a81615368565b905061551960208301856146f4565b818103604083015261552b8184614bfb565b90509392505050565b600060408201905061554960008301856146f4565b818103602083015261555b81846152d6565b90509392505050565b600060808201905061557960008301876146f4565b61558660208301866146f4565b61559360408301856147be565b81810360608301526155a581846152d6565b905095945050505050565b6000815190506155bf81614515565b92915050565b6000602082840312156155db576155da6144df565b5b60006155e9848285016155b0565b91505092915050565b6000819050919050565b61560d6156088261465f565b6155f2565b82525050565b600081905092915050565b6000615629826152ba565b6156338185615613565b93506156438185602086016145c0565b80840191505092915050565b600061565b82866155fc565b60208201915061566b828561561e565b915061567782846155fc565b602082019150819050949350505050565b7f4678526f6f7454756e6e656c3a20455849545f414c52454144595f50524f434560008201527f5353454400000000000000000000000000000000000000000000000000000000602082015250565b60006156e46024836145af565b91506156ef82615688565b604082019050919050565b60006020820190508181036000830152615713816156d7565b9050919050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f46585f4348494c445f5460008201527f554e4e454c000000000000000000000000000000000000000000000000000000602082015250565b60006157766025836145af565b91506157818261571a565b604082019050919050565b600060208201905081810360008301526157a581615769565b9050919050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f524543454950545f505260008201527f4f4f460000000000000000000000000000000000000000000000000000000000602082015250565b60006158086023836145af565b9150615813826157ac565b604082019050919050565b60006020820190508181036000830152615837816157fb565b9050919050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f5349474e415455524500600082015250565b6000615874601f836145af565b915061587f8261583e565b602082019050919050565b600060208201905081810360008301526158a381615867565b9050919050565b60006158bd6158b884614de7565b614dcc565b9050828152602081018484840111156158d9576158d8614d67565b5b6158e48482856145c0565b509392505050565b600082601f8301126159015761590061483b565b5b81516159118482602086016158aa565b91505092915050565b6000602082840312156159305761592f6144df565b5b600082015167ffffffffffffffff81111561594e5761594d6144e4565b5b61595a848285016158ec565b91505092915050565b600061596e8261465f565b91506159798361465f565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156159b2576159b161512a565b5b828202905092915050565b60006159c88261465f565b91506159d38361465f565b9250828210156159e6576159e561512a565b5b828203905092915050565b600081519050615a0081614b15565b92915050565b600081519050615a1581614669565b92915050565b600081519050615a2a8161471e565b92915050565b600080600080600060a08688031215615a4c57615a4b6144df565b5b6000615a5a888289016159f1565b9550506020615a6b88828901615a06565b9450506040615a7c88828901615a06565b9350506060615a8d88828901615a06565b9250506080615a9e88828901615a1b565b9150509295509295909350565b6000819050919050565b615ac6615ac18261478a565b615aab565b82525050565b6000615ad882876155fc565b602082019150615ae882866155fc565b602082019150615af88285615ab5565b602082019150615b088284615ab5565b60208201915081905095945050505050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f48454144455200000000600082015250565b6000615b50601c836145af565b9150615b5b82615b1a565b602082019050919050565b60006020820190508181036000830152615b7f81615b43565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000615bc08261465f565b9150615bcb8361465f565b925082615bdb57615bda615b86565b5b828206905092915050565b6000615bf18261465f565b9150615bfc8361465f565b925082615c0c57615c0b615b86565b5b828204905092915050565b600060ff82169050919050565b6000615c2f82615c17565b9150615c3a83615c17565b925082615c4a57615c49615b86565b5b828206905092915050565b6000615c6082615c17565b9150615c6b83615c17565b925082615c7b57615c7a615b86565b5b828204905092915050565b60008160011c9050919050565b6000808291508390505b6001851115615cdd57808604811115615cb957615cb861512a565b5b6001851615615cc85780820291505b8081029050615cd685615c86565b9450615c9d565b94509492505050565b600082615cf65760019050615db2565b81615d045760009050615db2565b8160018114615d1a5760028114615d2457615d53565b6001915050615db2565b60ff841115615d3657615d3561512a565b5b8360020a915084821115615d4d57615d4c61512a565b5b50615db2565b5060208310610133831016604e8410600b8410161715615d885782820a905083811115615d8357615d8261512a565b5b615db2565b615d958484846001615c93565b92509050818404811115615dac57615dab61512a565b5b81810290505b9392505050565b6000615dc48261465f565b9150615dcf8361465f565b9250615dfc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615ce6565b905092915050565b7f496e76616c69642070726f6f66206c656e677468000000000000000000000000600082015250565b6000615e3a6014836145af565b9150615e4582615e04565b602082019050919050565b60006020820190508181036000830152615e6981615e2d565b9050919050565b7f4c65616620696e64657820697320746f6f206269670000000000000000000000600082015250565b6000615ea66015836145af565b9150615eb182615e70565b602082019050919050565b60006020820190508181036000830152615ed581615e99565b9050919050565b6000615ee88285615ab5565b602082019150615ef88284615ab5565b6020820191508190509392505050565b6000615f1382615c17565b9150615f1e83615c17565b925082821015615f3157615f3061512a565b5b82820390509291505056fea264697066735822122095f2c7aa8b702b7d9ee463edbb4ea1564d2f604ceea72920974767f0fefaf41b64736f6c634300080b0033000000000000000000000000fe5e5d361b2ad62c541bab87c45a0b9b018389a200000000000000000000000086e4dc95c7fbdbf52e33d563bbdb00823894c287000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000a54656e746163756c6172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005544e54434c000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102275760003560e01c80638da5cb5b11610130578063b88d4fde116100b8578063ccea458f1161007c578063ccea458f1461069a578063de9b771f146106b8578063e985e9c5146106d6578063f2fde38b14610706578063f953cec71461072257610227565b8063b88d4fde146105e2578063c0857ba0146105fe578063c23dc68f1461061c578063c52141911461064c578063c87b56dd1461066a57610227565b806399a2557a116100ff57806399a2557a146105425780639b5719a614610572578063a22cb4651461058e578063aa22b45c146105aa578063aea4e49e146105c657610227565b80638da5cb5b146104b85780639094adb3146104d657806395d89b4114610506578063972c49281461052457610227565b806340c10f19116101b35780636352211e116101825780636352211e146103f057806370734dcf1461042057806370a082311461043c5780637bef587c1461046c5780638462151c1461048857610227565b806340c10f191461035857806342842e0e146103745780635bbb217714610390578063607f2d42146103c057610227565b80630e387de6116101fa5780630e387de6146102c657806318160ddd146102e45780631edc2e721461030257806323b872dd1461032057806330176e131461033c57610227565b806301ffc9a71461022c57806306fdde031461025c578063081812fc1461027a578063095ea7b3146102aa575b600080fd5b61024660048036038101906102419190614541565b61073e565b6040516102539190614589565b60405180910390f35b6102646107d0565b604051610271919061463d565b60405180910390f35b610294600480360381019061028f9190614695565b610862565b6040516102a19190614703565b60405180910390f35b6102c460048036038101906102bf919061474a565b6108e1565b005b6102ce610a25565b6040516102db91906147a3565b60405180910390f35b6102ec610a4c565b6040516102f991906147cd565b60405180910390f35b61030a610a63565b6040516103179190614589565b60405180910390f35b61033a600480360381019061033591906147e8565b610a76565b005b610356600480360381019061035191906148a0565b610d9b565b005b610372600480360381019061036d919061474a565b610e38565b005b61038e600480360381019061038991906147e8565b610f1b565b005b6103aa60048036038101906103a59190614943565b610f3b565b6040516103b79190614af3565b60405180910390f35b6103da60048036038101906103d59190614b41565b610ffe565b6040516103e79190614589565b60405180910390f35b61040a60048036038101906104059190614695565b61101e565b6040516104179190614703565b60405180910390f35b61043a60048036038101906104359190614943565b611030565b005b61045660048036038101906104519190614b6e565b6112ea565b60405161046391906147cd565b60405180910390f35b61048660048036038101906104819190614943565b6113a3565b005b6104a2600480360381019061049d9190614b6e565b61169c565b6040516104af9190614c59565b60405180910390f35b6104c06117e6565b6040516104cd9190614703565b60405180910390f35b6104f060048036038101906104eb9190614695565b61180c565b6040516104fd9190614589565b60405180910390f35b61050e61182c565b60405161051b919061463d565b60405180910390f35b61052c6118be565b6040516105399190614703565b60405180910390f35b61055c60048036038101906105579190614c7b565b6118e4565b6040516105699190614c59565b60405180910390f35b61058c60048036038101906105879190614b6e565b611af8565b005b6105a860048036038101906105a39190614cfa565b611bc3565b005b6105c460048036038101906105bf9190614d3a565b611cce565b005b6105e060048036038101906105db9190614b6e565b611d72565b005b6105fc60048036038101906105f79190614e97565b611e3d565b005b610606611eb0565b6040516106139190614f79565b60405180910390f35b61063660048036038101906106319190614695565b611ed6565b6040516106439190614fe9565b60405180910390f35b610654611f40565b60405161066191906147a3565b60405180910390f35b610684600480360381019061067f9190614695565b611f64565b604051610691919061463d565b60405180910390f35b6106a2612003565b6040516106af91906147a3565b60405180910390f35b6106c0612027565b6040516106cd9190615025565b60405180910390f35b6106f060048036038101906106eb9190615040565b61204d565b6040516106fd9190614589565b60405180910390f35b610720600480360381019061071b9190614b6e565b6120e1565b005b61073c60048036038101906107379190615080565b6121ac565b005b60006301ffc9a760e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061079957506380ac58cd60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806107c95750635b5e139f60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6060600280546107df906150f8565b80601f016020809104026020016040519081016040528092919081815260200182805461080b906150f8565b80156108585780601f1061082d57610100808354040283529160200191610858565b820191906000526020600020905b81548152906001019060200180831161083b57829003601f168201915b5050505050905090565b600061086d826121c6565b6108a3576040517fcf4700e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60006108ec8261101e565b90508073ffffffffffffffffffffffffffffffffffffffff1661090d612225565b73ffffffffffffffffffffffffffffffffffffffff16146109705761093981610934612225565b61204d565b61096f576040517fcfb3b94200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b826006600084815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b7f8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b03660001b81565b6000610a5661222d565b6001546000540303905090565b600f60009054906101000a900460ff1681565b6000610a8182612232565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610ae8576040517fa114810000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080610af484612300565b91509150610b0a8187610b05612225565b612327565b610b5657610b1f86610b1a612225565b61204d565b610b55576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161415610bbd576040517fea553b3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bca868686600161236b565b8015610bd557600082555b600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081546001900391905081905550600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815460010191905081905550610ca385610c7f8888876124de565b7c020000000000000000000000000000000000000000000000000000000017612506565b600460008681526020019081526020016000208190555060007c020000000000000000000000000000000000000000000000000000000084161415610d2b576000600185019050600060046000838152602001908152602001600020541415610d29576000548114610d28578360046000838152602001908152602001600020819055505b5b505b838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4610d938686866001612531565b505050505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610e22576040517fbfcafd3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8181600e9190610e33929190614362565b505050565b600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ebf576040517ff90715e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115b481610ecb612537565b610ed59190615159565b1115610f0d576040517fd05cb60900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f17828261254a565b5050565b610f3683838360405180602001604052806000815250611e3d565b505050565b6060600083839050905060008167ffffffffffffffff811115610f6157610f60614d6c565b5b604051908082528060200260200182016040528015610f9a57816020015b610f876143e8565b815260200190600190039081610f7f5790505b50905060005b828114610ff257610fc9868683818110610fbd57610fbc6151af565b5b90506020020135611ed6565b828281518110610fdc57610fdb6151af565b5b6020026020010181905250806001019050610fa0565b50809250505092915050565b600c6020528060005260406000206000915054906101000a900460ff1681565b600061102982612232565b9050919050565b600080339050803b91503273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580611076575060008214155b156110ad576040517f5a156d6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b84849050811015611235573373ffffffffffffffffffffffffffffffffffffffff166110f48686848181106110e8576110e76151af565b5b9050602002013561101e565b73ffffffffffffffffffffffffffffffffffffffff1614611141576040517feea91ff800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600015156010600087878581811061115c5761115b6151af565b5b90506020020135815260200190815260200160002060009054906101000a900460ff16151514156111dd5784848281811061119a576111996151af565b5b905060200201356040517fd0078a0a0000000000000000000000000000000000000000000000000000000081526004016111d491906147cd565b60405180910390fd5b6000601060008787858181106111f6576111f56151af565b5b90506020020135815260200190815260200160002060006101000a81548160ff021916908315150217905550808061122d906151de565b9150506110b0565b5060007f46ea84878955907861000722f4dd80a932935b7b3669b3a736e54d8ed9dca5c633868660405160200161126e93929190615288565b60405160208183030381529060405260405160200161128e92919061530f565b60405160208183030381529060405290507f137b854e7e99f3421d5319954d65a2fb8cd25a72297f898f1e662f0843b727d53386866040516112d29392919061538b565b60405180910390a16112e381612707565b5050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611352576040517f8f4eb60400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054169050919050565b600f60009054906101000a900460ff166113e9576040517f78d9002800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080339050803b91503273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158061142f575060008214155b15611466576040517f5a156d6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b848490508110156115e7573373ffffffffffffffffffffffffffffffffffffffff166114ad8686848181106114a1576114a06151af565b5b9050602002013561101e565b73ffffffffffffffffffffffffffffffffffffffff16146114fa576040517feea91ff800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60106000868684818110611511576115106151af565b5b90506020020135815260200190815260200160002060009054906101000a900460ff161561158f5784848281811061154c5761154b6151af565b5b905060200201356040517f3de74d5b00000000000000000000000000000000000000000000000000000000815260040161158691906147cd565b60405180910390fd5b6001601060008787858181106115a8576115a76151af565b5b90506020020135815260200190815260200160002060006101000a81548160ff02191690831515021790555080806115df906151de565b915050611469565b5060007f49a368f7e595a507e0eaa27f07cfde74ff475d8dafcdf3829d5d9b4a75f28a8433868660405160200161162093929190615288565b60405160208183030381529060405260405160200161164092919061530f565b60405160208183030381529060405290507f137b854e7e99f3421d5319954d65a2fb8cd25a72297f898f1e662f0843b727d53386866040516116849392919061541c565b60405180910390a161169581612707565b5050505050565b606060008060006116ac856112ea565b905060008167ffffffffffffffff8111156116ca576116c9614d6c565b5b6040519080825280602002602001820160405280156116f85781602001602082028036833780820191505090505b5090506117036143e8565b600061170d61222d565b90505b8386146117d857611720816127bb565b9150816040015115611731576117cd565b600073ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff161461177157816000015194505b8773ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614156117cc57808387806001019850815181106117bf576117be6151af565b5b6020026020010181815250505b5b806001019050611710565b508195505050505050919050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60106020528060005260406000206000915054906101000a900460ff1681565b60606003805461183b906150f8565b80601f0160208091040260200160405190810160405280929190818152602001828054611867906150f8565b80156118b45780601f10611889576101008083540402835291602001916118b4565b820191906000526020600020905b81548152906001019060200180831161189757829003601f168201915b5050505050905090565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606081831061191f576040517f32c1995a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061192a6127e6565b905061193461222d565b8510156119465761194361222d565b94505b80841115611952578093505b600061195d876112ea565b90508486101561198057600086860390508181101561197a578091505b50611985565b600090505b60008167ffffffffffffffff8111156119a1576119a0614d6c565b5b6040519080825280602002602001820160405280156119cf5781602001602082028036833780820191505090505b50905060008214156119e75780945050505050611af1565b60006119f288611ed6565b905060008160400151611a0757816000015190505b60008990505b888114158015611a1d5750848714155b15611ae357611a2b816127bb565b9250826040015115611a3c57611ad8565b600073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff1614611a7c57826000015191505b8a73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611ad75780848880600101995081518110611aca57611ac96151af565b5b6020026020010181815250505b5b806001019050611a0d565b508583528296505050505050505b9392505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611b7f576040517fbfcafd3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b8060076000611bd0612225565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16611c7d612225565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611cc29190614589565b60405180910390a35050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611d55576040517fbfcafd3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600f60006101000a81548160ff02191690831515021790555050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611df9576040517fbfcafd3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600b60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b611e48848484610a76565b60008373ffffffffffffffffffffffffffffffffffffffff163b14611eaa57611e73848484846127ef565b611ea9576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b50505050565b600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b611ede6143e8565b611ee66143e8565b611eee61222d565b831080611f025750611efe6127e6565b8310155b15611f105780915050611f3b565b611f19836127bb565b9050806040015115611f2e5780915050611f3b565b611f3783612940565b9150505b919050565b7f49a368f7e595a507e0eaa27f07cfde74ff475d8dafcdf3829d5d9b4a75f28a8481565b6060611f6f826121c6565b611fa5576040517fa14c4b5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611faf612960565b9050600081511415611fd05760405180602001604052806000815250611ffb565b80611fda846129f2565b604051602001611feb92919061549d565b6040516020818303038152906040525b915050919050565b7f46ea84878955907861000722f4dd80a932935b7b3669b3a736e54d8ed9dca5c681565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612168576040517fbfcafd3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006121b782612a42565b90506121c281612d47565b5050565b6000816121d161222d565b111580156121e0575060005482105b801561221e575060007c0100000000000000000000000000000000000000000000000000000000600460008581526020019081526020016000205416145b9050919050565b600033905090565b600090565b6000808290508061224161222d565b116122c9576000548110156122c85760006004600083815260200190815260200160002054905060007c0100000000000000000000000000000000000000000000000000000000821614156122c6575b60008114156122bc576004600083600190039350838152602001908152602001600020549050612291565b80925050506122fb565b505b5b6040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b60008060006006600085815260200190815260200160002090508092508254915050915091565b600073ffffffffffffffffffffffffffffffffffffffff8316925073ffffffffffffffffffffffffffffffffffffffff821691508382148383141790509392505050565b6010600083815260200190815260200160002060009054906101000a900460ff16156124d85760006010600084815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600167ffffffffffffffff8111156123da576123d9614d6c565b5b6040519080825280602002602001820160405280156124085781602001602082028036833780820191505090505b50905082816000815181106124205761241f6151af565b5b60200260200101818152505060007f46ea84878955907861000722f4dd80a932935b7b3669b3a736e54d8ed9dca5c686836040516020016124629291906154c1565b60405160208183030381529060405260405160200161248292919061530f565b60405160208183030381529060405290507f137b854e7e99f3421d5319954d65a2fb8cd25a72297f898f1e662f0843b727d586836040516124c49291906154f1565b60405180910390a16124d581612707565b50505b50505050565b60008060e883901c905060e86124f5868684612d4a565b62ffffff16901b9150509392505050565b600073ffffffffffffffffffffffffffffffffffffffff83169250814260a01b178317905092915050565b50505050565b600061254161222d565b60005403905090565b600080549050600082141561258b576040517fb562e8dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612598600084838561236b565b600160406001901b178202600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555061260f8361260060008660006124de565b61260985612d53565b17612506565b6004600083815260200190815260200160002081905550600080838301905073ffffffffffffffffffffffffffffffffffffffff85169150828260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600183015b8181146126b057808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600181019050612675565b5060008214156126ec576040517f2e07630000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060008190555050506127026000848385612531565b505050565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b4720477600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401612786929190615534565b600060405180830381600087803b1580156127a057600080fd5b505af11580156127b4573d6000803e3d6000fd5b5050505050565b6127c36143e8565b6127df6004600084815260200190815260200160002054612d63565b9050919050565b60008054905090565b60008373ffffffffffffffffffffffffffffffffffffffff1663150b7a02612815612225565b8786866040518563ffffffff1660e01b81526004016128379493929190615564565b6020604051808303816000875af192505050801561287357506040513d601f19601f8201168201806040525081019061287091906155c5565b60015b6128ed573d80600081146128a3576040519150601f19603f3d011682016040523d82523d6000602084013e6128a8565b606091505b506000815114156128e5576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050949350505050565b6129486143e8565b61295961295483612232565b612d63565b9050919050565b6060600e805461296f906150f8565b80601f016020809104026020016040519081016040528092919081815260200182805461299b906150f8565b80156129e85780601f106129bd576101008083540402835291602001916129e8565b820191906000526020600020905b8154815290600101906020018083116129cb57829003601f168201915b5050505050905090565b606060806040510190508060405280825b600115612a2e57600183039250600a81066030018353600a8104905080612a2957612a2e565b612a03565b508181036020830392508083525050919050565b60606000612a4f83612e19565b90506000612a5c82612e4d565b90506000612a6983612e7e565b9050600081612a7784612eaf565b612a80866130c5565b604051602001612a929392919061564f565b60405160208183030381529060405280519060200120905060001515600c600083815260200190815260200160002060009054906101000a900460ff16151514612b11576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b08906156fa565b60405180910390fd5b6001600c600083815260200190815260200160002060006101000a81548160ff0219169083151502179055506000612b48856130f6565b90506000612b558261321b565b9050612b6081613292565b73ffffffffffffffffffffffffffffffffffffffff16600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612bef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612be69061578c565b60405180910390fd5b6000612bfa876132c3565b9050612c18612c08846132f7565b87612c128a613305565b84613336565b612c57576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c4e9061581e565b60405180910390fd5b612c8585612c648961363c565b612c6d8a61366d565b84612c778c6136a1565b612c808d6136d2565b613703565b506000612c918361384a565b90507f8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b03660001b612cd3612cce60008461388f90919063ffffffff16565b6138be565b60001b14612d16576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d0d9061588a565b60405180910390fd5b6000612d2184613941565b806020019051810190612d34919061591a565b9050809950505050505050505050919050565b50565b60009392505050565b60006001821460e11b9050919050565b612d6b6143e8565b81816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060a082901c816020019067ffffffffffffffff16908167ffffffffffffffff168152505060007c01000000000000000000000000000000000000000000000000000000008316141581604001901515908115158152505060e882901c816060019062ffffff16908162ffffff1681525050919050565b612e21614437565b6000612e34612e2f84613972565b6139a0565b9050604051806020016040528082815250915050919050565b6060612e778260000151600881518110612e6a57612e696151af565b5b6020026020010151613ab5565b9050919050565b6000612ea88260000151600281518110612e9b57612e9a6151af565b5b60200260200101516138be565b9050919050565b606060006040518060200160405280600081525090506000835111156130bc57600080612edd600086613b6c565b60f81c905060018160ff161480612ef7575060038160ff16145b15612fc157600160028651612f0c9190615963565b612f1691906159bd565b67ffffffffffffffff811115612f2f57612f2e614d6c565b5b6040519080825280601f01601f191660200182016040528015612f615781602001600182028036833780820191505090505b5092506000612f71600187613b6c565b90508084600081518110612f8857612f876151af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600192505061302d565b6002808651612fd09190615963565b612fda91906159bd565b67ffffffffffffffff811115612ff357612ff2614d6c565b5b6040519080825280601f01601f1916602001820160405280156130255781602001600182028036833780820191505090505b509250600091505b60008260ff1690505b83518110156130b85761306360028460ff168361305391906159bd565b61305d9190615159565b87613b6c565b848281518110613076576130756151af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080806130b0906151de565b915050613036565b5050505b80915050919050565b60006130ef82600001516009815181106130e2576130e16151af565b5b60200260200101516138be565b9050919050565b6130fe61444a565b6131268260000151600681518110613119576131186151af565b5b6020026020010151613ab5565b8160200181905250600061313d8260200151613972565b905061314881613c04565b1561316357613156816139a0565b8260000181905250613203565b60008260200151905060006001825161317c91906159bd565b67ffffffffffffffff81111561319557613194614d6c565b5b6040519080825280601f01601f1916602001820160405280156131c75781602001600182028036833780820191505090505b5090506000808360210191508260200190506131e582828551613c52565b6131f66131f184613972565b6139a0565b8660000181905250505050505b61320c836130c5565b82604001818152505050919050565b61322361446b565b600061324d83600001516003815181106132405761323f6151af565b5b60200260200101516139a0565b836040015181518110613263576132626151af565b5b602002602001015190506040518060400160405280828152602001613287836139a0565b815250915050919050565b60006132bc82602001516000815181106132af576132ae6151af565b5b6020026020010151613cfd565b9050919050565b60006132ed82600001516005815181106132e0576132df6151af565b5b60200260200101516138be565b60001b9050919050565b606081602001519050919050565b606061332f8260000151600781518110613322576133216151af565b5b6020026020010151613ab5565b9050919050565b60008061334284613972565b9050600061334f826139a0565b905060608060008690506000806133658b612eaf565b9050600081511415613381576000975050505050505050613634565b60005b865181101561362b5781518311156133a757600098505050505050505050613634565b6133ca8782815181106133bd576133bc6151af565b5b6020026020010151613d20565b9550858051906020012084146133eb57600098505050505050505050613634565b61340e878281518110613401576134006151af565b5b60200260200101516139a0565b945060118551141561350157815183141561347e578c8051906020012061344f86601081518110613442576134416151af565b5b6020026020010151613ab5565b80519060200120141561346d57600198505050505050505050613634565b600098505050505050505050613634565b6000828481518110613493576134926151af565b5b602001015160f81c60f81b60f81c905060108160ff1611156134c15760009950505050505050505050613634565b6134e7868260ff16815181106134da576134d96151af565b5b6020026020010151613db0565b60001b94506001846134f99190615159565b935050613618565b60028551141561360657600061353b61353487600081518110613527576135266151af565b5b6020026020010151613ab5565b8486613de7565b90508251818561354b9190615159565b14156135ae578d8051906020012061357d876001815181106135705761356f6151af565b5b6020026020010151613ab5565b80519060200120141561359c5760019950505050505050505050613634565b60009950505050505050505050613634565b60008114156135c95760009950505050505050505050613634565b80846135d59190615159565b93506135fb866001815181106135ee576135ed6151af565b5b6020026020010151613db0565b60001b945050613617565b600098505050505050505050613634565b5b8080613623906151de565b915050613384565b50505050505050505b949350505050565b60006136668260000151600381518110613659576136586151af565b5b60200260200101516138be565b9050919050565b6000613697826000015160048151811061368a576136896151af565b5b60200260200101516138be565b60001b9050919050565b60006136cb82600001516000815181106136be576136bd6151af565b5b60200260200101516138be565b9050919050565b60606136fc82600001516001815181106136ef576136ee6151af565b5b6020026020010151613ab5565b9050919050565b600080600080600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166341539d4a876040518263ffffffff1660e01b815260040161376491906147cd565b60a060405180830381865afa158015613781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a59190615a30565b50935050925092506137fb828b6137bc91906159bd565b84878d8d8d8d6040516020016137d59493929190615acc565b60405160208183030381529060405280519060200120613f1d909392919063ffffffff16565b61383a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161383190615b66565b60405180910390fd5b8093505050509695505050505050565b61385261448b565b60405180602001604052806138858460200151600181518110613878576138776151af565b5b60200260200101516139a0565b8152509050919050565b61389761449e565b826000015182815181106138ae576138ad6151af565b5b6020026020010151905092915050565b60008082600001511180156138d857506021826000015111155b6138e157600080fd5b60006138f0836020015161408e565b9050600081846000015161390491906159bd565b90506000808386602001516139199190615159565b905080519150602083101561393557826020036101000a820491505b81945050505050919050565b606061396b826020015160028151811061395e5761395d6151af565b5b6020026020010151613ab5565b9050919050565b61397a61449e565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606139ab82613c04565b6139b457600080fd5b60006139bf8361414d565b905060008167ffffffffffffffff8111156139dd576139dc614d6c565b5b604051908082528060200260200182016040528015613a1657816020015b613a0361449e565b8152602001906001900390816139fb5790505b5090506000613a28856020015161408e565b8560200151613a379190615159565b9050600080600090505b84811015613aa857613a52836141db565b9150604051806040016040528083815260200184815250848281518110613a7c57613a7b6151af565b5b60200260200101819052508183613a939190615159565b92508080613aa0906151de565b915050613a41565b5082945050505050919050565b60606000826000015111613ac857600080fd5b6000613ad7836020015161408e565b90506000818460000151613aeb91906159bd565b905060008167ffffffffffffffff811115613b0957613b08614d6c565b5b6040519080825280601f01601f191660200182016040528015613b3b5781602001600182028036833780820191505090505b5090506000816020019050613b60848760200151613b599190615159565b82856142b7565b81945050505050919050565b600080600284613b7c9190615bb5565b14613bbf57601082600285613b919190615be6565b81518110613ba257613ba16151af565b5b602001015160f81c60f81b60f81c613bba9190615c24565b613bf9565b601082600285613bcf9190615be6565b81518110613be057613bdf6151af565b5b602001015160f81c60f81b60f81c613bf89190615c55565b5b60f81b905092915050565b60008082600001511415613c1b5760009050613c4d565b60008083602001519050805160001a915060c060ff168260ff161015613c4657600092505050613c4d565b6001925050505b919050565b6000811415613c6057613cf8565b5b602060ff168110613cab5782518252602060ff1683613c809190615159565b9250602060ff1682613c929190615159565b9150602060ff1681613ca491906159bd565b9050613c61565b6000811415613cb957613cf8565b6000600182602060ff16613ccd91906159bd565b610100613cda9190615db9565b613ce491906159bd565b905080198451168184511681811785525050505b505050565b60006015826000015114613d1057600080fd5b613d19826138be565b9050919050565b60606000826000015167ffffffffffffffff811115613d4257613d41614d6c565b5b6040519080825280601f01601f191660200182016040528015613d745781602001600182028036833780820191505090505b509050600081511415613d8a5780915050613dab565b6000816020019050613da584602001518286600001516142b7565b81925050505b919050565b60006021826000015114613dc357600080fd5b60008060018460200151613dd79190615159565b9050805191508192505050919050565b600080600090506000613df986612eaf565b90506000815167ffffffffffffffff811115613e1857613e17614d6c565b5b6040519080825280601f01601f191660200182016040528015613e4a5781602001600182028036833780820191505090505b50905060008590505b825186613e609190615159565b811015613eeb576000878281518110613e7c57613e7b6151af565b5b602001015160f81c60f81b905080838884613e9791906159bd565b81518110613ea857613ea76151af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350508080613ee3906151de565b915050613e53565b50808051906020012082805190602001201415613f0b5781519250613f10565b600092505b8293505050509392505050565b60008060208351613f2e9190615bb5565b14613f6e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613f6590615e50565b60405180910390fd5b600060208351613f7e9190615be6565b9050806002613f8d9190615db9565b8510613fce576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613fc590615ebc565b60405180910390fd5b6000808790506000602090505b8551811161407d578086015192506000600289613ff89190615bb5565b141561402e578183604051602001614011929190615edc565b60405160208183030381529060405280519060200120915061405a565b8282604051602001614041929190615edc565b6040516020818303038152906040528051906020012091505b6002886140679190615be6565b97506020816140769190615159565b9050613fdb565b508581149350505050949350505050565b600080825160001a9050608060ff168110156140ae576000915050614148565b60b860ff168110806140d3575060c060ff1681101580156140d2575060f860ff1681105b5b156140e2576001915050614148565b60c060ff1681101561411d5760018060b86140fd9190615f08565b60ff168261410b91906159bd565b6141159190615159565b915050614148565b60018060f861412c9190615f08565b60ff168261413a91906159bd565b6141449190615159565b9150505b919050565b6000808260000151141561416457600090506141d6565b600080614174846020015161408e565b84602001516141839190615159565b905060008460000151856020015161419b9190615159565b90505b808210156141cf576141af826141db565b826141ba9190615159565b915082806141c7906151de565b93505061419e565b8293505050505b919050565b6000806000835160001a9050608060ff168110156141fc57600191506142ad565b60b860ff1681101561422b576001608060ff168261421a91906159bd565b6142249190615159565b91506142ac565b60c060ff1681101561425b5760b78103600185019450806020036101000a855104600182018101935050506142ab565b60f860ff1681101561428a57600160c060ff168261427991906159bd565b6142839190615159565b91506142aa565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156142c55761435d565b5b602060ff1681106143105782518252602060ff16836142e59190615159565b9250602060ff16826142f79190615159565b9150602060ff168161430991906159bd565b90506142c6565b600081141561431e5761435d565b6000600182602060ff1661433291906159bd565b61010061433f9190615db9565b61434991906159bd565b905080198451168184511681811785525050505b505050565b82805461436e906150f8565b90600052602060002090601f01602090048101928261439057600085556143d7565b82601f106143a957803560ff19168380011785556143d7565b828001600101855582156143d7579182015b828111156143d65782358255916020019190600101906143bb565b5b5090506143e491906144b8565b5090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600067ffffffffffffffff168152602001600015158152602001600062ffffff1681525090565b6040518060200160405280606081525090565b60405180606001604052806060815260200160608152602001600081525090565b604051806040016040528061447e61449e565b8152602001606081525090565b6040518060200160405280606081525090565b604051806040016040528060008152602001600081525090565b5b808211156144d15760008160009055506001016144b9565b5090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61451e816144e9565b811461452957600080fd5b50565b60008135905061453b81614515565b92915050565b600060208284031215614557576145566144df565b5b60006145658482850161452c565b91505092915050565b60008115159050919050565b6145838161456e565b82525050565b600060208201905061459e600083018461457a565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156145de5780820151818401526020810190506145c3565b838111156145ed576000848401525b50505050565b6000601f19601f8301169050919050565b600061460f826145a4565b61461981856145af565b93506146298185602086016145c0565b614632816145f3565b840191505092915050565b600060208201905081810360008301526146578184614604565b905092915050565b6000819050919050565b6146728161465f565b811461467d57600080fd5b50565b60008135905061468f81614669565b92915050565b6000602082840312156146ab576146aa6144df565b5b60006146b984828501614680565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006146ed826146c2565b9050919050565b6146fd816146e2565b82525050565b600060208201905061471860008301846146f4565b92915050565b614727816146e2565b811461473257600080fd5b50565b6000813590506147448161471e565b92915050565b60008060408385031215614761576147606144df565b5b600061476f85828601614735565b925050602061478085828601614680565b9150509250929050565b6000819050919050565b61479d8161478a565b82525050565b60006020820190506147b86000830184614794565b92915050565b6147c78161465f565b82525050565b60006020820190506147e260008301846147be565b92915050565b600080600060608486031215614801576148006144df565b5b600061480f86828701614735565b935050602061482086828701614735565b925050604061483186828701614680565b9150509250925092565b600080fd5b600080fd5b600080fd5b60008083601f8401126148605761485f61483b565b5b8235905067ffffffffffffffff81111561487d5761487c614840565b5b60208301915083600182028301111561489957614898614845565b5b9250929050565b600080602083850312156148b7576148b66144df565b5b600083013567ffffffffffffffff8111156148d5576148d46144e4565b5b6148e18582860161484a565b92509250509250929050565b60008083601f8401126149035761490261483b565b5b8235905067ffffffffffffffff8111156149205761491f614840565b5b60208301915083602082028301111561493c5761493b614845565b5b9250929050565b6000806020838503121561495a576149596144df565b5b600083013567ffffffffffffffff811115614978576149776144e4565b5b614984858286016148ed565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6149c5816146e2565b82525050565b600067ffffffffffffffff82169050919050565b6149e8816149cb565b82525050565b6149f78161456e565b82525050565b600062ffffff82169050919050565b614a15816149fd565b82525050565b608082016000820151614a3160008501826149bc565b506020820151614a4460208501826149df565b506040820151614a5760408501826149ee565b506060820151614a6a6060850182614a0c565b50505050565b6000614a7c8383614a1b565b60808301905092915050565b6000602082019050919050565b6000614aa082614990565b614aaa818561499b565b9350614ab5836149ac565b8060005b83811015614ae6578151614acd8882614a70565b9750614ad883614a88565b925050600181019050614ab9565b5085935050505092915050565b60006020820190508181036000830152614b0d8184614a95565b905092915050565b614b1e8161478a565b8114614b2957600080fd5b50565b600081359050614b3b81614b15565b92915050565b600060208284031215614b5757614b566144df565b5b6000614b6584828501614b2c565b91505092915050565b600060208284031215614b8457614b836144df565b5b6000614b9284828501614735565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b614bd08161465f565b82525050565b6000614be28383614bc7565b60208301905092915050565b6000602082019050919050565b6000614c0682614b9b565b614c108185614ba6565b9350614c1b83614bb7565b8060005b83811015614c4c578151614c338882614bd6565b9750614c3e83614bee565b925050600181019050614c1f565b5085935050505092915050565b60006020820190508181036000830152614c738184614bfb565b905092915050565b600080600060608486031215614c9457614c936144df565b5b6000614ca286828701614735565b9350506020614cb386828701614680565b9250506040614cc486828701614680565b9150509250925092565b614cd78161456e565b8114614ce257600080fd5b50565b600081359050614cf481614cce565b92915050565b60008060408385031215614d1157614d106144df565b5b6000614d1f85828601614735565b9250506020614d3085828601614ce5565b9150509250929050565b600060208284031215614d5057614d4f6144df565b5b6000614d5e84828501614ce5565b91505092915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b614da4826145f3565b810181811067ffffffffffffffff82111715614dc357614dc2614d6c565b5b80604052505050565b6000614dd66144d5565b9050614de28282614d9b565b919050565b600067ffffffffffffffff821115614e0257614e01614d6c565b5b614e0b826145f3565b9050602081019050919050565b82818337600083830152505050565b6000614e3a614e3584614de7565b614dcc565b905082815260208101848484011115614e5657614e55614d67565b5b614e61848285614e18565b509392505050565b600082601f830112614e7e57614e7d61483b565b5b8135614e8e848260208601614e27565b91505092915050565b60008060008060808587031215614eb157614eb06144df565b5b6000614ebf87828801614735565b9450506020614ed087828801614735565b9350506040614ee187828801614680565b925050606085013567ffffffffffffffff811115614f0257614f016144e4565b5b614f0e87828801614e69565b91505092959194509250565b6000819050919050565b6000614f3f614f3a614f35846146c2565b614f1a565b6146c2565b9050919050565b6000614f5182614f24565b9050919050565b6000614f6382614f46565b9050919050565b614f7381614f58565b82525050565b6000602082019050614f8e6000830184614f6a565b92915050565b608082016000820151614faa60008501826149bc565b506020820151614fbd60208501826149df565b506040820151614fd060408501826149ee565b506060820151614fe36060850182614a0c565b50505050565b6000608082019050614ffe6000830184614f94565b92915050565b600061500f82614f46565b9050919050565b61501f81615004565b82525050565b600060208201905061503a6000830184615016565b92915050565b60008060408385031215615057576150566144df565b5b600061506585828601614735565b925050602061507685828601614735565b9150509250929050565b600060208284031215615096576150956144df565b5b600082013567ffffffffffffffff8111156150b4576150b36144e4565b5b6150c084828501614e69565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061511057607f821691505b60208210811415615124576151236150c9565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006151648261465f565b915061516f8361465f565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156151a4576151a361512a565b5b828201905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006151e98261465f565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561521c5761521b61512a565b5b600182019050919050565b600080fd5b60006152388385614ba6565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561526b5761526a615227565b5b60208302925061527c838584614e18565b82840190509392505050565b600060408201905061529d60008301866146f4565b81810360208301526152b081848661522c565b9050949350505050565b600081519050919050565b600082825260208201905092915050565b60006152e1826152ba565b6152eb81856152c5565b93506152fb8185602086016145c0565b615304816145f3565b840191505092915050565b60006040820190506153246000830185614794565b818103602083015261533681846152d6565b90509392505050565b7f554e424f554e4400000000000000000000000000000000000000000000000000600082015250565b60006153756007836145af565b91506153808261533f565b602082019050919050565b600060608201905081810360008301526153a481615368565b90506153b360208301866146f4565b81810360408301526153c681848661522c565b9050949350505050565b7f424f554e44000000000000000000000000000000000000000000000000000000600082015250565b60006154066005836145af565b9150615411826153d0565b602082019050919050565b60006060820190508181036000830152615435816153f9565b905061544460208301866146f4565b818103604083015261545781848661522c565b9050949350505050565b600081905092915050565b6000615477826145a4565b6154818185615461565b93506154918185602086016145c0565b80840191505092915050565b60006154a9828561546c565b91506154b5828461546c565b91508190509392505050565b60006040820190506154d660008301856146f4565b81810360208301526154e88184614bfb565b90509392505050565b6000606082019050818103600083015261550a81615368565b905061551960208301856146f4565b818103604083015261552b8184614bfb565b90509392505050565b600060408201905061554960008301856146f4565b818103602083015261555b81846152d6565b90509392505050565b600060808201905061557960008301876146f4565b61558660208301866146f4565b61559360408301856147be565b81810360608301526155a581846152d6565b905095945050505050565b6000815190506155bf81614515565b92915050565b6000602082840312156155db576155da6144df565b5b60006155e9848285016155b0565b91505092915050565b6000819050919050565b61560d6156088261465f565b6155f2565b82525050565b600081905092915050565b6000615629826152ba565b6156338185615613565b93506156438185602086016145c0565b80840191505092915050565b600061565b82866155fc565b60208201915061566b828561561e565b915061567782846155fc565b602082019150819050949350505050565b7f4678526f6f7454756e6e656c3a20455849545f414c52454144595f50524f434560008201527f5353454400000000000000000000000000000000000000000000000000000000602082015250565b60006156e46024836145af565b91506156ef82615688565b604082019050919050565b60006020820190508181036000830152615713816156d7565b9050919050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f46585f4348494c445f5460008201527f554e4e454c000000000000000000000000000000000000000000000000000000602082015250565b60006157766025836145af565b91506157818261571a565b604082019050919050565b600060208201905081810360008301526157a581615769565b9050919050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f524543454950545f505260008201527f4f4f460000000000000000000000000000000000000000000000000000000000602082015250565b60006158086023836145af565b9150615813826157ac565b604082019050919050565b60006020820190508181036000830152615837816157fb565b9050919050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f5349474e415455524500600082015250565b6000615874601f836145af565b915061587f8261583e565b602082019050919050565b600060208201905081810360008301526158a381615867565b9050919050565b60006158bd6158b884614de7565b614dcc565b9050828152602081018484840111156158d9576158d8614d67565b5b6158e48482856145c0565b509392505050565b600082601f8301126159015761590061483b565b5b81516159118482602086016158aa565b91505092915050565b6000602082840312156159305761592f6144df565b5b600082015167ffffffffffffffff81111561594e5761594d6144e4565b5b61595a848285016158ec565b91505092915050565b600061596e8261465f565b91506159798361465f565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156159b2576159b161512a565b5b828202905092915050565b60006159c88261465f565b91506159d38361465f565b9250828210156159e6576159e561512a565b5b828203905092915050565b600081519050615a0081614b15565b92915050565b600081519050615a1581614669565b92915050565b600081519050615a2a8161471e565b92915050565b600080600080600060a08688031215615a4c57615a4b6144df565b5b6000615a5a888289016159f1565b9550506020615a6b88828901615a06565b9450506040615a7c88828901615a06565b9350506060615a8d88828901615a06565b9250506080615a9e88828901615a1b565b9150509295509295909350565b6000819050919050565b615ac6615ac18261478a565b615aab565b82525050565b6000615ad882876155fc565b602082019150615ae882866155fc565b602082019150615af88285615ab5565b602082019150615b088284615ab5565b60208201915081905095945050505050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f48454144455200000000600082015250565b6000615b50601c836145af565b9150615b5b82615b1a565b602082019050919050565b60006020820190508181036000830152615b7f81615b43565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000615bc08261465f565b9150615bcb8361465f565b925082615bdb57615bda615b86565b5b828206905092915050565b6000615bf18261465f565b9150615bfc8361465f565b925082615c0c57615c0b615b86565b5b828204905092915050565b600060ff82169050919050565b6000615c2f82615c17565b9150615c3a83615c17565b925082615c4a57615c49615b86565b5b828206905092915050565b6000615c6082615c17565b9150615c6b83615c17565b925082615c7b57615c7a615b86565b5b828204905092915050565b60008160011c9050919050565b6000808291508390505b6001851115615cdd57808604811115615cb957615cb861512a565b5b6001851615615cc85780820291505b8081029050615cd685615c86565b9450615c9d565b94509492505050565b600082615cf65760019050615db2565b81615d045760009050615db2565b8160018114615d1a5760028114615d2457615d53565b6001915050615db2565b60ff841115615d3657615d3561512a565b5b8360020a915084821115615d4d57615d4c61512a565b5b50615db2565b5060208310610133831016604e8410600b8410161715615d885782820a905083811115615d8357615d8261512a565b5b615db2565b615d958484846001615c93565b92509050818404811115615dac57615dab61512a565b5b81810290505b9392505050565b6000615dc48261465f565b9150615dcf8361465f565b9250615dfc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615ce6565b905092915050565b7f496e76616c69642070726f6f66206c656e677468000000000000000000000000600082015250565b6000615e3a6014836145af565b9150615e4582615e04565b602082019050919050565b60006020820190508181036000830152615e6981615e2d565b9050919050565b7f4c65616620696e64657820697320746f6f206269670000000000000000000000600082015250565b6000615ea66015836145af565b9150615eb182615e70565b602082019050919050565b60006020820190508181036000830152615ed581615e99565b9050919050565b6000615ee88285615ab5565b602082019150615ef88284615ab5565b6020820191508190509392505050565b6000615f1382615c17565b9150615f1e83615c17565b925082821015615f3157615f3061512a565b5b82820390509291505056fea264697066735822122095f2c7aa8b702b7d9ee463edbb4ea1564d2f604ceea72920974767f0fefaf41b64736f6c634300080b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000fe5e5d361b2ad62c541bab87c45a0b9b018389a200000000000000000000000086e4dc95c7fbdbf52e33d563bbdb00823894c287000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000a54656e746163756c6172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005544e54434c000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _checkpointManager (address): 0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2
Arg [1] : _fxRoot (address): 0x86E4Dc95c7FBdBf52e33D563BbDB00823894C287
Arg [2] : name (string): Tentacular
Arg [3] : symbol (string): TNTCL
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000fe5e5d361b2ad62c541bab87c45a0b9b018389a2
Arg [1] : 00000000000000000000000086e4dc95c7fbdbf52e33d563bbdb00823894c287
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [4] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [5] : 54656e746163756c617200000000000000000000000000000000000000000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [7] : 544e54434c000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
[ 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.