Feature Tip: Add private address tag to any address under My Name Tag !
ERC-721
Overview
Max Total Supply
2,000 TMGG
Holders
969
Total Transfers
-
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
Tamagogi
Compiler Version
v0.8.7+commit.e28d00a7
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // ___ __ __ __ // | /\ |\/| /\ / _ / \/ _ | // | /--\| |/--\\__)\__/\__)| // // Tamagogi is a fully onchain tamagotchi dapp. // https://tamagogi.xyz pragma solidity ^0.8.7; import "https://github.com/RollaProject/solidity-datetime/blob/master/contracts/DateTimeContract.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "erc721a/contracts/ERC721A.sol"; import "base64-sol/base64.sol"; import "./tamagogi_drawer.sol"; contract Tamagogi is Ownable, ERC721A, ReentrancyGuard, TamagogiDrawer { struct TMGG { string name; uint lastFeed; uint lastPlay; uint lastHit; uint birthhash; } struct PetMdata { uint tokenId; uint seed; uint hunger; uint bored; uint unhappiness; bool isMaster; } struct Config { uint price; uint propMaxSupply; uint petMaxSupply; uint[3] hungerRate; uint[3] boredRate; uint[3] hitRate; uint[3] hitRasing; uint[5] reactionRate; bool revealProp; bool revealPet; MintStage mintStage; } //@@@ enum enum MintStage { PAUSED, PROPS, PETS_MERKLE, PETS } //@@@ event event EPlay( uint tokenId, address sender ); event EHit( uint tokenId, address sender ); event EFeed( uint tokenId, address sender ); constructor() ERC721A("Tamagogi", "TMGG") { config.price = 0; config.propMaxSupply = 2000; config.petMaxSupply = 1825; config.mintStage = MintStage.PAUSED; config.hungerRate = [8,40,120]; config.boredRate = [6,30,90]; config.hitRate = [4,20,60]; config.hitRasing = [9,3,1]; config.reactionRate = [0,10,20,30,40]; config.revealProp = false; config.revealPet = false; } DateTimeContract private dateTimeContract = new DateTimeContract(); bytes32 public rootHash = 0x0; Config public config; mapping(uint => uint) private seeds; mapping(uint => TMGG) public TMGGs; mapping(uint => bool) public rerollTable; mapping(string => bool) public nameTable; mapping(address => bool) public propMinted; mapping(address => bool) public petMinted; uint private bornTimestamp = 1640995201; uint private bornIdx = 0; //@@@ modifier modifier validToken(uint tokenId) { require(tokenId >= _startTokenId() && tokenId <= _totalMinted(), "Not valid id"); _; } modifier validOwner(uint tokenId) { require(ownerOf(tokenId) == msg.sender, "You are not token's owner"); _; } modifier revealPetOnly() { require(config.revealPet, "Not reveal"); _; } modifier petOnly(uint tokenId) { require(tokenId > config.propMaxSupply && tokenId <= config.petMaxSupply, "Not valid pet id"); _; } //@@@ mint function getProp() external payable { require(config.mintStage == MintStage.PROPS, "Not in stage to buy prop"); require(_totalMinted() < config.propMaxSupply, "No props left"); require(!propMinted[msg.sender], "Max to 1"); uint propId = _startTokenId() + _totalMinted(); uint seed = _getRandom(propId); seeds[propId] = seed; _safeMint(msg.sender, 1); propMinted[msg.sender] = true; } function hatchEgg() external payable { require(config.mintStage == MintStage.PETS, "Not in stage to mint TMGG"); require(_totalMinted() < config.petMaxSupply, "No pet left"); require(!petMinted[msg.sender], "Max to 1"); require(1 * config.price <= msg.value,"No enough eth."); _hatchEgg(); } function allowlistHatchEgg(bytes32[] calldata _proof) external payable { require(config.mintStage == MintStage.PETS_MERKLE, "Not in stage to mint merkle TMGG"); require(_totalMinted() < config.petMaxSupply, "No pet left"); require(!petMinted[msg.sender], "Max to 1"); require(1 * config.price <= msg.value,"No enough eth."); bytes32 leaf = keccak256(abi.encodePacked(msg.sender)); require(MerkleProof.verify(_proof, rootHash, leaf), "invalid proof"); _hatchEgg(); } function _hatchEgg() private { uint mintId = _startTokenId() + _totalMinted(); if (bornIdx == 5) { bornIdx = 0; bornTimestamp = dateTimeContract.addDays(bornTimestamp, 1); } TMGG memory preBornTMGG = TMGG('', block.timestamp, block.timestamp, 0, bornTimestamp); TMGGs[mintId] = preBornTMGG; bornIdx++; uint seed = _getRandom(mintId); seeds[mintId] = seed; _safeMint(msg.sender, 1); petMinted[msg.sender] = true; } //@@@ pet function function setName(uint tokenId, string calldata name) external validOwner(tokenId) revealPetOnly() petOnly(tokenId) { require(nameTable[name] == false, "Name exist"); uint nameLength = utfStringLength(name); require(nameLength > 1 && nameLength < 18, "Not valid name"); TMGGs[tokenId].name = name; nameTable[name] = true; } // everyone can call these function to feed, hit or play with any pet function play(uint tokenId) external revealPetOnly() petOnly(tokenId) { TMGGs[tokenId].lastPlay = block.timestamp; emit EPlay(tokenId, msg.sender); } function feed(uint tokenId) external revealPetOnly() petOnly(tokenId) { TMGGs[tokenId].lastFeed = block.timestamp; emit EFeed(tokenId, msg.sender); } function hit(uint tokenId) external revealPetOnly() petOnly(tokenId) { TMGGs[tokenId].lastHit = block.timestamp; emit EHit(tokenId, msg.sender); } function reroll(uint tokenId) external validOwner(tokenId) revealPetOnly() petOnly(tokenId) { require(!rerollTable[tokenId], "Not available"); seeds[tokenId] = _getRandom(tokenId); rerollTable[tokenId] = true; } function isBirthdate(uint tokenId) public view petOnly(tokenId) returns (bool) { TMGG memory tmgg = TMGGs[tokenId]; uint _now = block.timestamp; uint seed = seeds[tokenId]; uint offset = seed % 31536000; return dateTimeContract.getDay(_now) == dateTimeContract.getDay(tmgg.birthhash + offset) && dateTimeContract.getMonth(_now) == dateTimeContract.getMonth(tmgg.birthhash + offset); } function getBirthdate(uint tokenId) public view petOnly(tokenId) returns (uint month, uint day) { TMGG memory tmgg = TMGGs[tokenId]; uint seed = seeds[tokenId]; uint offset = seed % 31536000; uint _month = dateTimeContract.getMonth(tmgg.birthhash + offset); uint _day = dateTimeContract.getDay(tmgg.birthhash + offset); return (_month, _day); } function getPetUnhappinessAndProp(uint tokenId) public view revealPetOnly() petOnly(tokenId) returns(uint, bool, bool ,bool) { uint _now = block.timestamp; TMGG memory tmgg = TMGGs[tokenId]; uint hunger = dateTimeContract.diffHours(tmgg.lastFeed, _now); uint bored = dateTimeContract.diffHours(tmgg.lastPlay, _now); uint _baseHit = tmgg.lastHit == 0 ? 0 : (_now - tmgg.lastHit) / 60; uint hitVal = 0; if (_baseHit <= config.hitRate[0]) { hitVal = _baseHit * config.hitRasing[0]; } else if (_baseHit < config.hitRate[1]) { hitVal = _baseHit * config.hitRasing[1]; } else if (_baseHit < config.hitRate[2]) { hitVal = _baseHit * config.hitRasing[2]; } else { hitVal = _baseHit * 0; } uint[] memory ownerTokens = tokensOfOwner(ownerOf(tokenId)); bool ownFood = false; bool ownToy = false; bool ownShield = false; for(uint i = 0; i < ownerTokens.length; i++) { uint id = ownerTokens[i]; if (id <= config.propMaxSupply) { uint seed = seeds[id]; uint propNumber = propOdds[seed % propOdds.length]; if (propNumber == 0) { // own food hunger = 0; ownFood = true; } else if (propNumber == 1) { // own toy bored = 0; ownToy = true; } else if (propNumber == 2) { // own shiled hitVal = 0; ownShield = true; } } } uint _unhappiness = hunger + bored + hitVal; return (_unhappiness, ownFood, ownToy, ownShield); } function getPetHungerAndBored(uint tokenId) public view revealPetOnly() petOnly(tokenId) returns(uint, uint) { uint _now = block.timestamp; TMGG memory tmgg = TMGGs[tokenId]; uint hunger = dateTimeContract.diffHours(tmgg.lastFeed, _now); uint bored = dateTimeContract.diffHours(tmgg.lastPlay, _now); uint[] memory ownerTokens = tokensOfOwner(ownerOf(tokenId)); for(uint i = 0; i < ownerTokens.length; i++) { uint id = ownerTokens[i]; if (id <= config.propMaxSupply) { uint seed = seeds[id]; uint propNumber = propOdds[seed % propOdds.length]; if (propNumber == 0) { // own food hunger = 0; } else if (propNumber == 1) { // own toy bored = 0; } } } return (hunger, bored); } function _getReactionTraitIndex(uint _unhappiness) private view returns (uint) { if (_unhappiness <= config.reactionRate[0]) { return reaction[3]; } else if (_unhappiness < config.reactionRate[1]) { return reaction[0]; } else if (_unhappiness < config.reactionRate[2]) { return reaction[1]; } else if (_unhappiness < config.reactionRate[3]) { return reaction[2]; } else { return reaction[4]; } } function _getPetTraits(PetMdata memory petMeta) private pure returns (string memory) { string memory attr = string(abi.encodePacked( '{ "trait_type": "hunger", "display_type": "number", "value": ',Strings.toString(petMeta.hunger),'},', '{ "trait_type": "bored", "display_type": "number", "value": ',Strings.toString(petMeta.bored),'},' )); return attr; } function _getPetStyleTraits(PetMdata memory petMeta) private view returns (string memory) { string memory masterLabel = petMeta.isMaster ? "yes" : "no"; string memory attr = string(abi.encodePacked( '{ "trait_type": "type", "value": "pets"},', '{ "trait_type": "master", "value": "',masterLabel,'"},', '{ "trait_type": "unhappiness", "display_type": "number", "value": ',Strings.toString(petMeta.unhappiness),'},', _getPetReactionTraits(petMeta), _getPetEarTraits(petMeta), _getPetHeadTraits(petMeta), _getPetBodyTraits(petMeta) )); return attr; } function _getPetReactionTraits(PetMdata memory petMeta) private view returns (string memory) { string memory attr = string(abi.encodePacked( '{ "trait_type": "reaction", "value": "',reactionTraits[_getReactionTraitIndex(petMeta.unhappiness)],'"},' )); return attr; } function _getPetEarTraits(PetMdata memory petMeta) private view returns (string memory) { string memory attr = string(abi.encodePacked( '{ "trait_type": "ear", "value": "',earTraits[ear[(petMeta.seed / 2) % ear.length]],'"},' )); return attr; } function _getPetHeadTraits(PetMdata memory petMeta) private view returns (string memory) { string memory attr = string(abi.encodePacked( '{ "trait_type": "head", "value": "',headTraits[head[(petMeta.seed / 3) % head.length]],'"},' )); return attr; } function _getPetBodyTraits(PetMdata memory petMeta) private view returns (string memory) { string memory attr = string(abi.encodePacked( '{ "trait_type": "body", "value": "',bodyTraits[body[(petMeta.seed / 4) % body.length]],'"},' )); return attr; } function _getPetsName(PetMdata memory petMeta) private view returns (string memory) { (uint month, uint day) = getBirthdate(petMeta.tokenId); TMGG memory tmgg = TMGGs[petMeta.tokenId]; string memory name = utfStringLength(tmgg.name) > 1 ? string(abi.encodePacked(tmgg.name, " / ")) : ""; return string(abi.encodePacked( '{"name": "',name,'#',Strings.toString(petMeta.tokenId),' Tamagogi (',Strings.toString(month),'/',Strings.toString(day),')','",' )); } function _getPetsBirthTrait(PetMdata memory petMeta) private view returns (string memory) { (uint month, uint day) = getBirthdate(petMeta.tokenId); return string(abi.encodePacked( '{ "trait_type": "birthdate", "value": "',Strings.toString(month),'/',Strings.toString(day),'"}' )); } function _getPetsMetadata(uint tokenId) private view returns (string memory) { (uint unhappiness, bool ownFood, bool ownToy, bool ownShield) = getPetUnhappinessAndProp(tokenId); (uint hunger, uint bored) = getPetHungerAndBored(tokenId); bool hbd = isBirthdate(tokenId); bool isMaster = ownFood && ownToy && ownShield || hbd ? true : false; uint reactionId = _getReactionTraitIndex(unhappiness); PetMdata memory petMeta = PetMdata(tokenId, seeds[tokenId], hunger, bored, unhappiness, isMaster); string memory _svgString = drawReveal(seeds[tokenId], reactionId, isMaster); string memory json = string( abi.encodePacked( _getPetsName(petMeta), '"description": "Tamagogi is a Tamagotchi Dapp and fully generated on-chain. The contract interaction and time will affect the status and reaction of the pet. If you collect other items, the pet will show love!",', '"attributes": [', _getPetTraits(petMeta), _getPetStyleTraits(petMeta), _getPetsBirthTrait(petMeta), '],' '"image": "data:image/svg+xml;base64,', Base64.encode(bytes(drawSVG(_svgString))), '"}' ) ); return Base64.encode( bytes( string(json) ) ); } function _getPetsUnrevealMetadata(uint tokenId) private view returns (string memory) { (uint month, uint day) = getBirthdate(tokenId); uint _seed = seeds[tokenId]; string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "#',Strings.toString(tokenId),' Tamagogi Egg (',Strings.toString(month),'/',Strings.toString(day),')','", "description": "Unbroken Tamagogi eggs...",', '"attributes": [', '{ "trait_type": "type", "value": "pets"},', '{ "trait_type": "birthdate", "value": "',Strings.toString(month),'/',Strings.toString(day),'"}', '],', '"image": "ipfs://QmW1tccYqBmSLQFTfN8rWw8JHXxx7hZS4MiiwWWDN5tvG8/',Strings.toString(eggs[_seed % eggs.length]),'.gif"}' ) ) ) ); return json; } function _getPropsMetadata(uint tokenId) private view returns (string memory) { uint _seed = seeds[tokenId]; uint _propIndex = propOdds[_seed % propOdds.length]; string memory _desc = propDesc[_propIndex]; string memory _traitName = propTraits[_propIndex]; string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "#',Strings.toString(tokenId),' Tamagogi (',_traitName,')", "description": "',_desc,'",', '"attributes": [', '{ "trait_type": "type", "value": "props"},', '{ "trait_type": "usage", "value": "',_traitName,'"}' '],', '"image": "ipfs://QmVxCDfmwgY2psAh7wti8aLCykkj99snygGQ89p2zkfAtf/',_traitName,'.gif"}' ) ) ) ); return json; } function _getPropsUnrevealMetadata(uint tokenId) private pure returns (string memory) { string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "#',Strings.toString(tokenId),' Tamagogi (Unreveal Props)", "description": "Unreveal Props",', '"attributes": [', '{ "trait_type": "type", "value": "props"}', '],', '"image": "ipfs://QmTbB6DD2w8t36zLPvBEdoWo62RFMyJi9EXcj99ZixPrxC"}' ) ) ) ); return json; } //@@@ override function _tokenURI(uint256 tokenId) private view validToken(tokenId) returns (string memory) { string memory json = tokenId <= config.propMaxSupply ? config.revealProp ? _getPropsMetadata(tokenId) : _getPropsUnrevealMetadata(tokenId) : config.revealPet ? _getPetsMetadata(tokenId) : _getPetsUnrevealMetadata(tokenId); return string(abi.encodePacked('data:application/json;base64,', json)); } function tokenURI(uint256 tokenId) override (ERC721A) public view returns (string memory) { return _tokenURI(tokenId); } function _startTokenId() override internal pure virtual returns (uint256) { return 1; } //@@@ admin function setMintStage(uint _stage) external onlyOwner { config.mintStage = MintStage(_stage); } function setHungerRate(uint[3] calldata _rate) external onlyOwner { config.hungerRate = _rate; } function setBoredRate(uint[3] calldata _rate) external onlyOwner { config.boredRate = _rate; } function setHitRate(uint[3] calldata _rate) external onlyOwner { config.hitRate = _rate; } function setReactionRate(uint[5] calldata _rate) external onlyOwner { config.reactionRate = _rate; } function setHitRasing(uint[3] calldata _rate) external onlyOwner { config.hitRasing = _rate; } function setRevealPet() external onlyOwner { config.revealPet = true; } function setRevealProp() external onlyOwner { config.revealProp = true; } function setPrice(uint _price) external onlyOwner { config.price = _price; } function setMerkle(bytes32 _hash) external onlyOwner { rootHash = _hash; } //@@@ others // ERC721AQueryable.sol function tokensOfOwner(address owner) public view virtual 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; } } // https://ethereum.stackexchange.com/questions/13862/is-it-possible-to-check-string-variables-length-inside-the-contract function utfStringLength(string memory str) pure internal returns (uint length) { uint i=0; bytes memory string_rep = bytes(str); while (i<string_rep.length) { if (string_rep[i]>>7==0) i+=1; else if (string_rep[i]>>5==bytes1(uint8(0x6))) i+=2; else if (string_rep[i]>>4==bytes1(uint8(0xE))) i+=3; else if (string_rep[i]>>3==bytes1(uint8(0x1E))) i+=4; else //For safety i+=1; length++; } } function _getRandom(uint tokenId) private view returns (uint) { uint randomlize = uint(keccak256(abi.encodePacked(blockhash(block.number - 1), tokenId, msg.sender))); return randomlize; } }
pragma solidity ^0.8.7; import "base64-sol/base64.sol"; import "./tamagogi_data.sol"; // SPDX-License-Identifier: MIT contract TamagogiDrawer is TamagogiData { function drawImage(bytes memory trait) private pure returns (string memory) { return string(abi.encodePacked( '<image x="0" y="0" width="32" height="32" image-rendering="pixelated" preserveAspectRatio="xMidYMid" xlink:href="data:image/png;base64,',Base64.encode(bytes(trait)),'"/>' )); } function drawReveal(uint seed, uint reactionId, bool isMaster) internal view returns (string memory) { bytes memory bodyImageData = bodyBytes[(seed / 4) % body.length]; bytes memory headImageData = headBytes[(seed / 3) % head.length]; bytes memory earImageData = earBytes[(seed / 2) % ear.length]; bytes memory reactionImageData = reactionBytes[reactionId]; string memory imgString = string(abi.encodePacked( drawImage(bodyImageData), drawImage(headImageData), drawImage(reactionImageData), drawImage(earImageData) )); if (isMaster) { //master imgString = string(abi.encodePacked( imgString, drawImage(masterBytes[0]) )); } return imgString; } function drawSVG(string memory svgString) internal pure returns (string memory) { return string(abi.encodePacked( '<svg width="960" height="960" version="1.1" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">', '<rect width="100%" height="100%" fill="#aad999" />', svgString, "</svg>" )); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0; /// @title Base64 /// @author Brecht Devos - <[email protected]> /// @notice Provides functions for encoding/decoding base64 library Base64 { string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; bytes internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000" hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000" hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000" hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000"; function encode(bytes memory data) internal pure returns (string memory) { if (data.length == 0) return ''; // load the table into memory string memory table = TABLE_ENCODE; // multiply by 4/3 rounded up uint256 encodedLen = 4 * ((data.length + 2) / 3); // add some extra buffer at the end required for the writing string memory result = new string(encodedLen + 32); assembly { // set the actual output length mstore(result, encodedLen) // prepare the lookup table let tablePtr := add(table, 1) // input ptr let dataPtr := data let endPtr := add(dataPtr, mload(data)) // result ptr, jump over length let resultPtr := add(result, 32) // run over the input, 3 bytes at a time for {} lt(dataPtr, endPtr) {} { // read 3 bytes dataPtr := add(dataPtr, 3) let input := mload(dataPtr) // write 4 characters mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and( input, 0x3F)))) resultPtr := add(resultPtr, 1) } // padding with '=' switch mod(mload(data), 3) case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) } case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) } } return result; } function decode(string memory _data) internal pure returns (bytes memory) { bytes memory data = bytes(_data); if (data.length == 0) return new bytes(0); require(data.length % 4 == 0, "invalid base64 decoder input"); // load the table into memory bytes memory table = TABLE_DECODE; // every 4 characters represent 3 bytes uint256 decodedLen = (data.length / 4) * 3; // add some extra buffer at the end required for the writing bytes memory result = new bytes(decodedLen + 32); assembly { // padding with '=' let lastBytes := mload(add(data, mload(data))) if eq(and(lastBytes, 0xFF), 0x3d) { decodedLen := sub(decodedLen, 1) if eq(and(lastBytes, 0xFFFF), 0x3d3d) { decodedLen := sub(decodedLen, 1) } } // set the actual output length mstore(result, decodedLen) // prepare the lookup table let tablePtr := add(table, 1) // input ptr let dataPtr := data let endPtr := add(dataPtr, mload(data)) // result ptr, jump over length let resultPtr := add(result, 32) // run over the input, 4 characters at a time for {} lt(dataPtr, endPtr) {} { // read 4 characters dataPtr := add(dataPtr, 4) let input := mload(dataPtr) // write 3 bytes let output := add( add( shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)), shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))), add( shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)), and(mload(add(tablePtr, and( input , 0xFF))), 0xFF) ) ) mstore(resultPtr, shl(232, output)) resultPtr := add(resultPtr, 3) } } return result; } }
// 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 { if (operator == _msgSenderERC721A()) revert ApproveToCaller(); _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]`. 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. 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 aliged. // 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 // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The proofs can be generated using the JavaScript library * https://github.com/miguelmota/merkletreejs[merkletreejs]. * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. * * See `test/utils/cryptography/MerkleProof.test.js` for some examples. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the merkle tree could be reinterpreted as a leaf value. */ library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify( bytes32[] memory proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} * * _Available since v4.7._ */ function verifyCalldata( bytes32[] calldata proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. * * _Available since v4.4._ */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} * * _Available since v4.7._ */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * _Available since v4.7._ */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * _Available since v4.7._ */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`, * consuming from one or the other at each step according to the instructions given by * `proofFlags`. * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof} * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // ---------------------------------------------------------------------------- // DateTime Library v2.0 - Contract Instance // // A gas-efficient Solidity date and time library // // https://github.com/bokkypoobah/DateTime // // Tested date range 1970/01/01 to 2345/12/31 // // Conventions: // Unit | Range | Notes // :-------- |:-------------:|:----- // timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC // year | 1970 ... 2345 | // month | 1 ... 12 | // day | 1 ... 31 | // hour | 0 ... 23 | // minute | 0 ... 59 | // second | 0 ... 59 | // dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday // // // Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. // // GNU Lesser General Public License 3.0 // https://www.gnu.org/licenses/lgpl-3.0.en.html // ---------------------------------------------------------------------------- import "./DateTime.sol"; contract DateTimeContract { uint256 public constant SECONDS_PER_DAY = 24 * 60 * 60; uint256 public constant SECONDS_PER_HOUR = 60 * 60; uint256 public constant SECONDS_PER_MINUTE = 60; int256 public constant OFFSET19700101 = 2440588; uint256 public constant DOW_MON = 1; uint256 public constant DOW_TUE = 2; uint256 public constant DOW_WED = 3; uint256 public constant DOW_THU = 4; uint256 public constant DOW_FRI = 5; uint256 public constant DOW_SAT = 6; uint256 public constant DOW_SUN = 7; function _now() public view returns (uint256 timestamp) { timestamp = block.timestamp; } function _nowDateTime() public view returns (uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second) { (year, month, day, hour, minute, second) = DateTime.timestampToDateTime(block.timestamp); } function _daysFromDate(uint256 year, uint256 month, uint256 day) public pure returns (uint256 _days) { return DateTime._daysFromDate(year, month, day); } function _daysToDate(uint256 _days) public pure returns (uint256 year, uint256 month, uint256 day) { return DateTime._daysToDate(_days); } function timestampFromDate(uint256 year, uint256 month, uint256 day) public pure returns (uint256 timestamp) { return DateTime.timestampFromDate(year, month, day); } function timestampFromDateTime( uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second ) public pure returns (uint256 timestamp) { return DateTime.timestampFromDateTime(year, month, day, hour, minute, second); } function timestampToDate(uint256 timestamp) public pure returns (uint256 year, uint256 month, uint256 day) { (year, month, day) = DateTime.timestampToDate(timestamp); } function timestampToDateTime(uint256 timestamp) public pure returns (uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second) { (year, month, day, hour, minute, second) = DateTime.timestampToDateTime(timestamp); } function isValidDate(uint256 year, uint256 month, uint256 day) public pure returns (bool valid) { valid = DateTime.isValidDate(year, month, day); } function isValidDateTime(uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second) public pure returns (bool valid) { valid = DateTime.isValidDateTime(year, month, day, hour, minute, second); } function isLeapYear(uint256 timestamp) public pure returns (bool leapYear) { leapYear = DateTime.isLeapYear(timestamp); } function _isLeapYear(uint256 year) public pure returns (bool leapYear) { leapYear = DateTime._isLeapYear(year); } function isWeekDay(uint256 timestamp) public pure returns (bool weekDay) { weekDay = DateTime.isWeekDay(timestamp); } function isWeekEnd(uint256 timestamp) public pure returns (bool weekEnd) { weekEnd = DateTime.isWeekEnd(timestamp); } function getDaysInMonth(uint256 timestamp) public pure returns (uint256 daysInMonth) { daysInMonth = DateTime.getDaysInMonth(timestamp); } function _getDaysInMonth(uint256 year, uint256 month) public pure returns (uint256 daysInMonth) { daysInMonth = DateTime._getDaysInMonth(year, month); } function getDayOfWeek(uint256 timestamp) public pure returns (uint256 dayOfWeek) { dayOfWeek = DateTime.getDayOfWeek(timestamp); } function getYear(uint256 timestamp) public pure returns (uint256 year) { year = DateTime.getYear(timestamp); } function getMonth(uint256 timestamp) public pure returns (uint256 month) { month = DateTime.getMonth(timestamp); } function getDay(uint256 timestamp) public pure returns (uint256 day) { day = DateTime.getDay(timestamp); } function getHour(uint256 timestamp) public pure returns (uint256 hour) { hour = DateTime.getHour(timestamp); } function getMinute(uint256 timestamp) public pure returns (uint256 minute) { minute = DateTime.getMinute(timestamp); } function getSecond(uint256 timestamp) public pure returns (uint256 second) { second = DateTime.getSecond(timestamp); } function addYears(uint256 timestamp, uint256 _years) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.addYears(timestamp, _years); } function addMonths(uint256 timestamp, uint256 _months) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.addMonths(timestamp, _months); } function addDays(uint256 timestamp, uint256 _days) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.addDays(timestamp, _days); } function addHours(uint256 timestamp, uint256 _hours) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.addHours(timestamp, _hours); } function addMinutes(uint256 timestamp, uint256 _minutes) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.addMinutes(timestamp, _minutes); } function addSeconds(uint256 timestamp, uint256 _seconds) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.addSeconds(timestamp, _seconds); } function subYears(uint256 timestamp, uint256 _years) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.subYears(timestamp, _years); } function subMonths(uint256 timestamp, uint256 _months) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.subMonths(timestamp, _months); } function subDays(uint256 timestamp, uint256 _days) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.subDays(timestamp, _days); } function subHours(uint256 timestamp, uint256 _hours) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.subHours(timestamp, _hours); } function subMinutes(uint256 timestamp, uint256 _minutes) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.subMinutes(timestamp, _minutes); } function subSeconds(uint256 timestamp, uint256 _seconds) public pure returns (uint256 newTimestamp) { newTimestamp = DateTime.subSeconds(timestamp, _seconds); } function diffYears(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _years) { _years = DateTime.diffYears(fromTimestamp, toTimestamp); } function diffMonths(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _months) { _months = DateTime.diffMonths(fromTimestamp, toTimestamp); } function diffDays(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _days) { _days = DateTime.diffDays(fromTimestamp, toTimestamp); } function diffHours(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _hours) { _hours = DateTime.diffHours(fromTimestamp, toTimestamp); } function diffMinutes(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _minutes) { _minutes = DateTime.diffMinutes(fromTimestamp, toTimestamp); } function diffSeconds(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _seconds) { _seconds = DateTime.diffSeconds(fromTimestamp, toTimestamp); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // ---------------------------------------------------------------------------- // DateTime Library v2.0 // // A gas-efficient Solidity date and time library // // https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary // // Tested date range 1970/01/01 to 2345/12/31 // // Conventions: // Unit | Range | Notes // :-------- |:-------------:|:----- // timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC // year | 1970 ... 2345 | // month | 1 ... 12 | // day | 1 ... 31 | // hour | 0 ... 23 | // minute | 0 ... 59 | // second | 0 ... 59 | // dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday // // // Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. // ---------------------------------------------------------------------------- library DateTime { uint256 constant SECONDS_PER_DAY = 24 * 60 * 60; uint256 constant SECONDS_PER_HOUR = 60 * 60; uint256 constant SECONDS_PER_MINUTE = 60; int256 constant OFFSET19700101 = 2440588; uint256 constant DOW_MON = 1; uint256 constant DOW_TUE = 2; uint256 constant DOW_WED = 3; uint256 constant DOW_THU = 4; uint256 constant DOW_FRI = 5; uint256 constant DOW_SAT = 6; uint256 constant DOW_SUN = 7; // ------------------------------------------------------------------------ // Calculate the number of days from 1970/01/01 to year/month/day using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and subtracting the offset 2440588 so that 1970/01/01 is day 0 // // days = day // - 32075 // + 1461 * (year + 4800 + (month - 14) / 12) / 4 // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 // - offset // ------------------------------------------------------------------------ function _daysFromDate(uint256 year, uint256 month, uint256 day) internal pure returns (uint256 _days) { require(year >= 1970); int256 _year = int256(year); int256 _month = int256(month); int256 _day = int256(day); int256 __days = _day - 32075 + (1461 * (_year + 4800 + (_month - 14) / 12)) / 4 + (367 * (_month - 2 - ((_month - 14) / 12) * 12)) / 12 - (3 * ((_year + 4900 + (_month - 14) / 12) / 100)) / 4 - OFFSET19700101; _days = uint256(__days); } // ------------------------------------------------------------------------ // Calculate year/month/day from the number of days since 1970/01/01 using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and adding the offset 2440588 so that 1970/01/01 is day 0 // // int L = days + 68569 + offset // int N = 4 * L / 146097 // L = L - (146097 * N + 3) / 4 // year = 4000 * (L + 1) / 1461001 // L = L - 1461 * year / 4 + 31 // month = 80 * L / 2447 // dd = L - 2447 * month / 80 // L = month / 11 // month = month + 2 - 12 * L // year = 100 * (N - 49) + year + L // ------------------------------------------------------------------------ function _daysToDate(uint256 _days) internal pure returns (uint256 year, uint256 month, uint256 day) { unchecked { int256 __days = int256(_days); int256 L = __days + 68569 + OFFSET19700101; int256 N = (4 * L) / 146097; L = L - (146097 * N + 3) / 4; int256 _year = (4000 * (L + 1)) / 1461001; L = L - (1461 * _year) / 4 + 31; int256 _month = (80 * L) / 2447; int256 _day = L - (2447 * _month) / 80; L = _month / 11; _month = _month + 2 - 12 * L; _year = 100 * (N - 49) + _year + L; year = uint256(_year); month = uint256(_month); day = uint256(_day); } } function timestampFromDate(uint256 year, uint256 month, uint256 day) internal pure returns (uint256 timestamp) { timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; } function timestampFromDateTime( uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second ) internal pure returns (uint256 timestamp) { timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; } function timestampToDate(uint256 timestamp) internal pure returns (uint256 year, uint256 month, uint256 day) { unchecked { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); } } function timestampToDateTime(uint256 timestamp) internal pure returns (uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second) { unchecked { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); uint256 secs = timestamp % SECONDS_PER_DAY; hour = secs / SECONDS_PER_HOUR; secs = secs % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; second = secs % SECONDS_PER_MINUTE; } } function isValidDate(uint256 year, uint256 month, uint256 day) internal pure returns (bool valid) { if (year >= 1970 && month > 0 && month <= 12) { uint256 daysInMonth = _getDaysInMonth(year, month); if (day > 0 && day <= daysInMonth) { valid = true; } } } function isValidDateTime(uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second) internal pure returns (bool valid) { if (isValidDate(year, month, day)) { if (hour < 24 && minute < 60 && second < 60) { valid = true; } } } function isLeapYear(uint256 timestamp) internal pure returns (bool leapYear) { (uint256 year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); leapYear = _isLeapYear(year); } function _isLeapYear(uint256 year) internal pure returns (bool leapYear) { leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); } function isWeekDay(uint256 timestamp) internal pure returns (bool weekDay) { weekDay = getDayOfWeek(timestamp) <= DOW_FRI; } function isWeekEnd(uint256 timestamp) internal pure returns (bool weekEnd) { weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; } function getDaysInMonth(uint256 timestamp) internal pure returns (uint256 daysInMonth) { (uint256 year, uint256 month,) = _daysToDate(timestamp / SECONDS_PER_DAY); daysInMonth = _getDaysInMonth(year, month); } function _getDaysInMonth(uint256 year, uint256 month) internal pure returns (uint256 daysInMonth) { if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { daysInMonth = 31; } else if (month != 2) { daysInMonth = 30; } else { daysInMonth = _isLeapYear(year) ? 29 : 28; } } // 1 = Monday, 7 = Sunday function getDayOfWeek(uint256 timestamp) internal pure returns (uint256 dayOfWeek) { uint256 _days = timestamp / SECONDS_PER_DAY; dayOfWeek = ((_days + 3) % 7) + 1; } function getYear(uint256 timestamp) internal pure returns (uint256 year) { (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getMonth(uint256 timestamp) internal pure returns (uint256 month) { (, month,) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getDay(uint256 timestamp) internal pure returns (uint256 day) { (,, day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getHour(uint256 timestamp) internal pure returns (uint256 hour) { uint256 secs = timestamp % SECONDS_PER_DAY; hour = secs / SECONDS_PER_HOUR; } function getMinute(uint256 timestamp) internal pure returns (uint256 minute) { uint256 secs = timestamp % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; } function getSecond(uint256 timestamp) internal pure returns (uint256 second) { second = timestamp % SECONDS_PER_MINUTE; } function addYears(uint256 timestamp, uint256 _years) internal pure returns (uint256 newTimestamp) { (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY); year += _years; uint256 daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY); require(newTimestamp >= timestamp); } function addMonths(uint256 timestamp, uint256 _months) internal pure returns (uint256 newTimestamp) { (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY); month += _months; year += (month - 1) / 12; month = ((month - 1) % 12) + 1; uint256 daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY); require(newTimestamp >= timestamp); } function addDays(uint256 timestamp, uint256 _days) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp + _days * SECONDS_PER_DAY; require(newTimestamp >= timestamp); } function addHours(uint256 timestamp, uint256 _hours) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; require(newTimestamp >= timestamp); } function addMinutes(uint256 timestamp, uint256 _minutes) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; require(newTimestamp >= timestamp); } function addSeconds(uint256 timestamp, uint256 _seconds) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp + _seconds; require(newTimestamp >= timestamp); } function subYears(uint256 timestamp, uint256 _years) internal pure returns (uint256 newTimestamp) { (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY); year -= _years; uint256 daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY); require(newTimestamp <= timestamp); } function subMonths(uint256 timestamp, uint256 _months) internal pure returns (uint256 newTimestamp) { (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY); uint256 yearMonth = year * 12 + (month - 1) - _months; year = yearMonth / 12; month = (yearMonth % 12) + 1; uint256 daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY); require(newTimestamp <= timestamp); } function subDays(uint256 timestamp, uint256 _days) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp - _days * SECONDS_PER_DAY; require(newTimestamp <= timestamp); } function subHours(uint256 timestamp, uint256 _hours) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; require(newTimestamp <= timestamp); } function subMinutes(uint256 timestamp, uint256 _minutes) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; require(newTimestamp <= timestamp); } function subSeconds(uint256 timestamp, uint256 _seconds) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp - _seconds; require(newTimestamp <= timestamp); } function diffYears(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _years) { require(fromTimestamp <= toTimestamp); (uint256 fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); (uint256 toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); _years = toYear - fromYear; } function diffMonths(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _months) { require(fromTimestamp <= toTimestamp); (uint256 fromYear, uint256 fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); (uint256 toYear, uint256 toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; } function diffDays(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _days) { require(fromTimestamp <= toTimestamp); _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; } function diffHours(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _hours) { require(fromTimestamp <= toTimestamp); _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; } function diffMinutes(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _minutes) { require(fromTimestamp <= toTimestamp); _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; } function diffSeconds(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _seconds) { require(fromTimestamp <= toTimestamp); _seconds = toTimestamp - fromTimestamp; } }
// 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(); /** * The caller cannot approve to their own address. */ error ApproveToCaller(); /** * 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); }
pragma solidity ^0.8.7; // SPDX-License-Identifier: MIT contract TamagogiData { //@@@ props uint[10] internal propOdds = [0,0,0,0,1,1,1,1,2,2]; string[3] internal propTraits = ["food", "toy", "shield"]; string[3] internal propDesc = ["Food will be able to prevent your pet from starvation.","Toys can keep your pet from being bored.","Shield to protect your pet from being hit."]; //@@@ pets uint[3] internal eggs = [1,2,3]; uint[13] internal ear = [0,1,2,3,4,5,6,7,8,9,10,11,12]; uint[5] internal reaction = [0,1,2,3,4]; uint[11] internal head = [0,1,2,3,4,5,6,7,8,9,10]; uint[11] internal body = [0,1,2,3,4,5,6,7,8,9,10]; string[13] internal earTraits = ["Melody","Cinna","Racoon","Long ear","Dog","Teddy","Trapa","Shorthair","Rabbit","Mick","Mouse","Bear","Cat"]; string[5] internal reactionTraits = ["Normal","Angry","Sad","Smile","Upset"]; string[11] internal headTraits = ["Horn","Whiskers","Whiskers fat","Fluffy","Whiskers thin","Square","Hamster","Normal","Cricetinae","Naja","Plump"]; string[11] internal bodyTraits = ["Sit","Dress","Stand","Huddle up","Feeble","Star","Clothes","Strong","Squat","Hulk","Long legs"]; bytes[1] internal masterBytes = [bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af4000000017352474200aece1ce900000066494441545847edd5310e00100c85613d8efb1fc67108092961914a0dbfc540f25e3f0309ce4b9cf30305104000010410f84720c7982525e9fb8b5f7297d104eac11a58cb589638658c107dc13abc0fb2cb98a67cc9af4be8014d996f9e8c02082080000208145bcb2821effa51fe0000000049454e44ae426082')]; bytes[13] internal earBytes = [bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000080494441545847ed94410ac0200c04f5ff8f6ec921250475d7da22c87ad48d1927602d9b57dddcbf30005782ecd5e49c95c1fb51c02ecd196f14f75b3903e8ed3f6f1a01a0623f6773cd69af00f80b91ea21203382b70d284308c0b5cd6a8ef925032c401c4736f609c06fdf053b0201c8800cc8800cc8800cc8800cc8c0b9066edd51182171bab4cb0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000008f494441545847ed93d10e80200845f5ff3fba461b8de80a526daeedf6a628f778b4de167f7d717efb05c0662c09b01d23817e4d78c8cc8084d9357e8c004a7b228052234732bd1701a8e2cc4ef5fdc2be5eaf34ad2acf40908d3347c3d0ddeadcccbd8f20a21e476d04f0263483d1fa054026fdef96a97d52bf657cfdd0ca5004a0011aa0011aa0011aa0011aa0811d3de21d21bb35e40a0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006c494441545847edd4d10a4011108461deffa14951d2b2e342a8ff5c9d8bc98e8fc470f98b97e7876f0aa42aa51696f3ca8265b196ebff67a7b795f70a5803572576f3ee1d980d6bc4a382b5a1a5daf3026587cab92bf7c1cc7802c79f090a2080000208208000020820804006486e132187d8c7c60000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000072494441545847ed94510a00210844ebfe876e290844dacd8996085e7fd1a8e353cae9f0c987eba7a881628cce62146dc8404d688bfabb85a8685bdcac9baa51922ada7b0d742aa3fdf544bfc6b544a02fd8dbe8fcfb1603b6e3c8ce48fa68c2dfbe0b0c40000210800004200001084000020fc5ac172190ff741b0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000075494441545847ed92410ec0200804f5ff8f6ee381a4c12a0b1ebc8ce765990cf676f9f5cbfb5b04f038c0286f71796e57e84bac3c8248cdadca5625a7179bf6650046768029062ceb81cb00eaf2ef1ff88328016497ef206400af4e515f9a89ee79fae9c279003080010c60000318c0000630808117a9bd1321772d676e0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000007e494441545847ed92510ac0300843dbfb1f7a459820d22e993f52c8be0a33f1edad73343fb379ff60009e1792998ddf43e550a995f84c3c237174ee0b2097a0a5bbf7109e017095b6001973889c39da438595e52788ad410460a13fff3e2f81d92b002a978fce3006e8b2caa00064400664400664400664400664a0ddc00276971321672fab0a0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000074494441545847ed94310ec0200cc4e0ff8f2e4202d481e452a062317372674cd59c2e9f7cb93f298067027874c70b9b95771e6beff3ce4a9005e1959be03b0035b4ef47cadff3e365d57bd6c168b8f53dbb1d11801d08992f07dab5562dc87c39f0f77f02000c60000318c000063080010c60a000b8610b216fdcaceb0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000070494441545847ed92410ac0200c04f5ff8f6e9b4341aa761772082de34590641d27f656bc7af1fded3300c7652a609ffb28d0a999843b0676c1713eae15e0ddbb9db4029001c61f7acd5000919f8190bd0a4006fcde80f1c05c891a412edde806000318c000063080010c600003e5064e048315215641d2fc0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000068494441545847ed94610b00100c44f9ff3f9a28b5165792d6eaf9a6e1eede965a82570dd62fe90c3443cc9b57b523e81b0243c09eb77b55935d4e63c0271ca914015f7f6e41a8819df84ab406efd44a7577be7133035fbe0c0c40000210800004200001084000021df3d61521c08b49860000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000067494441545847ed93410a00200cc3f4ff8f56100411ba513d8810cfb5ed32ade5f1a98ff3cb1705da46292b6de95db3d945dddbc3337db80265a64c5dfdf08908b886aefebac03a40162e873d7d03eeef9539590137c8d6530002108000042000010840000210e80b6d0b213ce71b1e0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000068494441545847ed94c10a00101404f9ff8f2607a5478c835cc64dedee5b4372fabcf2e7f9c902844019ae89e89b1c7b4e812d68d4c4fdea095d796e0bc4d3ad0ac4cc6de953813e90e8088d49438309fa188e3cb4c0b3efc20212908004242001094840021290400533b70d21044e4ab70000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000065494441545847edd4dd0a00100c8661bbff8ba61d90ffad24a9d7216bfb3c8984c74b1ecf0fdf04889dd42ab8b7aeb4f30868d3beee64afb98b1560362837a8cfbc75c393238025a06416afd6ec1ee5768627c0d5af82000820800002082080000208209000f7ce15214de4787a0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006d494441545847ed93410ac0200c04f5ff8f5602e6225476410896e979b39d0cb1b7e2af17ffbf3d0130962517569a534ab32838947ce4e419a530ca22276db4e572f6f3d41c807db3d3fd66ef7500f7d1fc03c0dddaca2b376015ba61003080010c60000318c0000630506e6002f73b0f211a4494500000000049454e44ae426082')]; bytes[5] internal reactionBytes = [bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005f494441545847edd5bb0a00200846617dff87ae961a44f042e0721a237fe51b5265f8e8707f61000410400081aac03a5f77549379f3364014665745263cf3a63d80b7bb4a0d6d4055c013b977adac56d1cf15ce0008208000020820302eb00182580621fa639d260000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005e494441545847ed95390e00200cc3e8ff1fcd3180104294b64317334362792052928f24f717003080010c60c06aa0f6af5b7bf373672d8016769b8a5781a97c847b004e2873e91e100598e56e88284078cd01c000063080010c6020dd4003cbd40721aa0beb880000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000061494441545847ed95410a00200804ebff8f2e3a142115ae045ea6abad4e73b05a924f4d9e5f00c00006308001d540db56b7cdbe6ad78daf028c4663d02df7aa1d215400cf00cf9d05a302d8574cede13ee1e0af6f1c000c60000318c00006d20d745ccf0721d52fc6040000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005b494441545847edd5310e0020080441f9ffa3550a3b20014968d69620e714226bf8c8f0fc450004104000818ac0bedfb7d717d5cc5f3f1be00db006453577e56403b4efaedf00fa6a3de57bca8d5d1404400001041040008171810356ee0721ed9f05790000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000063494441545847ed954b0a00200844f3fe87eeb3898848cdc0cd6b6d33d3131a29c94792fd0b012000010840c04ba0f6af5bbb6399990da0899daae266e0321fe2de001603cb4c88c04a6598bd3ce45b80709b7b571036dc05080001084000021080400354df0721739252ba0000000049454e44ae426082')]; bytes[11] internal headBytes = [bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000074494441545847ed94410ec0200cc3e0ff8f66e3c01192954905c99c9bd432526b497e35797f01000318b8c6407befc557582be3945a45938326b30a4016189774d9b102f863f9e09b761d6d40d2efeaef7965a0cfec7c85cc3a005108b9dc3560988e8fb806e21b4412000c60000318c040ba81073af6102143c1dc740000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af4000000017352474200aece1ce900000072494441545847ed943112c0200804cf49feffe214190a6752c1450a2dd65a605d9021e9d2c63300c000063060187824dd8bbbaa8cad165199c0004b73380051a363208dcf0082bc537cca49f31c6d205eb0750666f10e4499a36ac1b78f7f07d10277018cdfb67605000c60000318c000065e01921281db558cba0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006a494441545847ed944b0a00200844ebfe87eeb310dae88404153c5741cc383cc55a2e57bddcbf10000210f882401bb7221b546a95b134d83864a14714e04473cbe77a7901a6c04a515210422f083c4b605d9ef9ceee81cddfd5678dd5e26dff130002108000042000810e4ece1021878663410000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005b494441545847ed94db0900200cc474ffa17d2c604a058b10bfbdf408b4bd15bf5e3cbf5940031af8c2c058b7225b14b3044640e0901d195460f36f4a60960a2040031a7861203023ff85b6204f0e262da0010d6840031a283730013af6102192d097b20000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000060494441545847edd6cb0a0020084451fdff8feeb16813e4580411dcd669c31124b7c7c71fbf6f044000812f044adb15a741656da6b16c122c33594b804860f049c6c408963dd4087ae138eaee9c23558bc02eebf5ef030110400001041040a0028cd31421444923dc0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000049494441545847edd6410a00200804c0fcffa3ab17a40421c17857973988319a2b9af70f010810f84260ee5b711b34edad0c4e871c8e59da2b0001021581a72f8300040810204080c0023af610215e442abd0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000064494441545847ed94490e00200803f1ff8f763978841a354193e16a6ceb80144bae92ec6f04800004be2050fbaed80d2aef2a6129b0b0c8428da703dc78fd04e46a79046e9a872108100de168c32835a8ea23843aa7e2ca5c9e13000210800004200081063eee1021a0220e8e0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000061494441545847ed94410e00100c04f5ff8f460f8eac20a926e3cc760cad95e065c1f50b0018c0400a03b5cf8a5350795605cb808d41b6ccf81ae0c5ed87a069d6ca403880d3bf80c8fb07e4fbdd76809f575db051e36e0b0018c000063080010c343af61021f9935c500000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000067494441545847ed954b0a00200805f3fe87eeb368994f2ab0605ae77318c3ac241f4bee5f00c00006be3050fbaed80595b5916019e22c33590b8032201506fe1237c303b8d17cf22db39e0618f4372c6c8f2030def32bea119e7710090060000318c00006d20d343af6102106b4da3d0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000060494441545847ed96410a00200804f3ff8f2e844e511a68e461bab74ea348d23e1ff95cbf0180010c9436d0e78e88429a39a770bd142dbceeb86d2600650d68ff32e7e098e50d5a068499e101444db80fb80178fa6500000318c00006308081013eee10210f9b3be30000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000072494441545847ed94310e00210804f5ff8ff68ec2c4e2803d43a2c55859c0b219597b3b7cfae1f90d031080804260bc5155eabe129df666c2a980f08f841a91818ae1d39fabe519a81c1e9ac0c0b504ecdd2af7e0f712ae8b63f72cae5e1a6d70d8bf2b2cc45f2bc10004200001084000020fec3f1221ce89b1720000000049454e44ae426082')]; bytes[11] internal bodyBytes = [bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000b9494441545847ed96c10e80200c4321faff5fec4139cce0dc68410c979178215bf7a81b21a794b6eb5bb672008403e14038100e8403e140384038705c31fbe08b05e6b20f1228640052390c0025e4380473110014207e4d53a30530a3b8f0b95a1ec08ce2b5c6278051189d67ea300e588965afac7a3cbd3d89e90228e2226815d2a22dbb2db0bb77d1140888770a298c00dc8b8c01d010f5e4590008fa31b97f01c0f193001640f70471ffbc9ad4cce901608b76c52d073801df502d81d35c52b50000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a4494441545847ed964b0ac0200c05957aff1377515d0444f2796ac1169e20144c759c1831a794aeda8fb54c001aa0011aa0011aa0011a000cdc35a62cbe58c27f9107493f49fb9636426963db00e304b3000dd685f00c788b2319e90d991016c0eee25a9a5488cf0248ee10d5688c5a494815ecc084e5fb2b006d375296d6d86b06ac7ab600c20b480e0e9a0289ef2f22eff0853b5f05404f3c1c376b009e180d3c0ef000b15d1d81d94175870000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a6494441545847ed96c10a80201883957aff27ee501e0493e9e6df218405dedcfcfe39c29c523a9ef5db970de0049c801370024ec009ec90c0f5409ec10703d5aaef016a0400258d0220190d12a25a06400d84ab997acc007ae10a8cac1d01208332ac5ac6a2eff7c30114802a8c24d06a96000a7d3f450400f9bc6ac34ad86e8e024c7bfa05a026540f68fb21c34601d001f4be51145b01d04281e2d2ffd44a02d42cb2c10037c7f12981ef4fbe3c0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a0494441545847ed96c10a8020104495faff2fee907b30ac5667b6840e8d10c4e2eaf3b98a39a5b494efb396052003322003322003322003a481adf45b83af162a877990500375e0602e02f006b098b5ab9151bc6b2f0ad00231ff063ab41001e84d58edb340a7dd8a00046bf0e83ecdc03f016011012daf8fa157606dac9ddf3b96f0f24245e81988dc03530dd4d5a2555540efb2baed1863e069f5537902d801343f25816dd4601b0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a2494441545847ed964b0ac030084413dafb9fb88bc642200dea980f94c204bad2eae4f92139a57494efb3932980044880044880044880040204aee2734ebe58e0bfe84102030484b9313c013b92577d66acdf098850d17cb612f04458b6ad02a4ae43b734fc9ffe18e981362912d0dba7086837954072acbda0d9a7c7108ed0ea0e402568e36b48b5fc2d99c8c4b83dd027a8782325f07c5e71d12a0e505e73a1801b9c8b2581c49959130000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000009e494441545847ed96410ac0200c0495f6ff2feea17a08b4c1646314bcacd05b930c936db19652aef61c3b9500344003344003344003341030f0b477eee48d05d6a20b496fd0cf0a805bef01ac0e17696e1f0b60d77008e10164b55b7119e621020083e404f45b3b05d07bca1a7684d0ec81be0201b1d68120a1bd1500dd7c346c1b80566835d63b87eb8b18d079404dd15a7e998d0224ffc4b88c00c70dbcedba1d81b2a5703a0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000092494441545847ed96410ac0200c0495f6ff2feea1061a0852bb9b40f1b282d0431227630af6d6da31f6b6d5052003322003322003322003a4816bc49dc9570b95c33e48ac586541680680ea644107731140b5f39967698201f0e42c4ccc2b0358277eb015612162ece71c2003b34a78a70f241c3e2f5c0160fe86df00e295d8f7db7cd0875b81ac01a6fb548c006460bb811b903311813716c23a0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000089494441545847ed96b10ac0200c4423edff7f7187ea60493378977490c2096e313edf29d8ccece873db68029001199001199001199001c2c0d56bcee28f05ae653e24b0c9020eae4500b0016166d9230bc000c59a7f030cc3e3047ea00b99aa4711c4882b112cafc95780795a6f85817ca0b2003192b9b1d78e227a19a900102f8f2f11800c6c37700360131781b4054f830000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000091494441545847ed96b10e80200c444be4ffbfd8411848c060efda05872371f2da3e5ed050ccec6acfb1550420033220033220033220038481bb656af2c6026bd90b096cb401a46a1800aad1872158fb7b00b803e26cb83d9081a30068f8fc3e925da47906224d23d934c07b8867c0cbd2003dc80e8dc084003c88dd507ae783027d0523d71b6716fc85b30099e1548d001e930027810fe7f6160000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000098494441545847ed964b0ac0200c0523f5fe27eea26621049b98f82952784237d53c27038a8988aef21d1b090030000330000330000330e018b8cb7c5e7cad7433220f921508b7d60370030276a60decd8bcf2995996819d9b77217e033063a4ad5133a2062c00fecf433baa9f03c80d34c02500eeaa76573bec055a736dc6ebd47af7802c90619a766f5ebd3246000277cef812001c37f00086f72381b52e906c0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000092494441545847ed96d10ac02008458dedffbf780fab072142f3ea06637083bd44dae9e8a2262247ff3e1b8d0034400334400334400334001ab8faba33f96a816290070994c8810b63770023788cecc957966d1e0f20244f96632c377322004f60e6d87f01a832355ded03adbfdb4bc85fe0d56f4e6e6d0095ae0a60255fe708f0aa01b429c3a65bef0fb4070af70e1642801b8ad723816807111a0000000049454e44ae426082')]; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","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":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"EFeed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"EHit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"EPlay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"TMGGs","outputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"lastFeed","type":"uint256"},{"internalType":"uint256","name":"lastPlay","type":"uint256"},{"internalType":"uint256","name":"lastHit","type":"uint256"},{"internalType":"uint256","name":"birthhash","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"allowlistHatchEgg","outputs":[],"stateMutability":"payable","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":"config","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"propMaxSupply","type":"uint256"},{"internalType":"uint256","name":"petMaxSupply","type":"uint256"},{"internalType":"bool","name":"revealProp","type":"bool"},{"internalType":"bool","name":"revealPet","type":"bool"},{"internalType":"enum Tamagogi.MintStage","name":"mintStage","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"feed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getBirthdate","outputs":[{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getPetHungerAndBored","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getPetUnhappinessAndProp","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProp","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"hatchEgg","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"hit","outputs":[],"stateMutability":"nonpayable","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":"uint256","name":"tokenId","type":"uint256"}],"name":"isBirthdate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"nameTable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"address","name":"","type":"address"}],"name":"petMinted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"play","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"propMinted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"reroll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rerollTable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","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":"uint256[3]","name":"_rate","type":"uint256[3]"}],"name":"setBoredRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[3]","name":"_rate","type":"uint256[3]"}],"name":"setHitRasing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[3]","name":"_rate","type":"uint256[3]"}],"name":"setHitRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[3]","name":"_rate","type":"uint256[3]"}],"name":"setHungerRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"}],"name":"setMerkle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stage","type":"uint256"}],"name":"setMintStage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[5]","name":"_rate","type":"uint256[5]"}],"name":"setReactionRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setRevealPet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setRevealProp","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":"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":[],"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"}]
Contract Creation Code
6101c06040526000608081815260a082905260c082905260e09190915260016101008190526101208190526101408190526101605260026101808190526101a0526200004f90600a908162001063565b506040805160a08101825260046060820190815263199bdbd960e21b6080830152815281518083018352600380825262746f7960e81b602083810191909152808401929092528351808501855260068152651cda1a595b1960d21b9281019290925292820152620000c49160149190620010ab565b506040805160c081019091526036606082018181528291620085d960808401398152602001604051806060016040528060288152602001620088dd6028913981526020016040518060600160405280602a815260200162009105602a9139905262000134906017906003620010ab565b5060408051606081018252600181526002602082015260039181018290526200016191601a9190620010fe565b50604080516101a08101825260008152600160208201526002918101919091526003606082015260046080820152600560a0820152600660c0820152600760e082015260086101008201526009610120820152600a610140820152600b610160820152600c610180820152620001dc90601d90600d62001133565b506040805160a081018252600081526001602082015260029181019190915260036060820152600460808201526200021990602a90600562001168565b50604080516101608101825260008152600160208201526002918101919091526003606082015260046080820152600560a0820152600660c0820152600760e082015260086101008201526009610120820152600a6101408201526200028490602f90600b6200119d565b50604080516101608101825260008152600160208201526002918101919091526003606082015260046080820152600560a0820152600660c0820152600760e082015260086101008201526009610120820152600a610140820152620002ef90603a90600b6200119d565b50604080516101e08101825260066101a08201818152654d656c6f647960d01b6101c084015282528251808401845260058082526443696e6e6160d81b6020838101919091528085019290925284518086018652838152652930b1b7b7b760d11b81840152848601528451808601865260088152672637b7339032b0b960c11b81840152606085015284518086018652600380825262446f6760e81b8285015260808601919091528551808701875282815264546564647960d81b8185015260a08601528551808701875282815264547261706160d81b8185015260c086015285518087018752600981526829b437b93a3430b4b960b91b8185015260e08601528551808701875293845265149858989a5d60d21b84840152610100850193909352845180860186526004808252634d69636b60e01b8285015261012086019190915285518087018752918252644d6f75736560d81b8284015261014085019190915284518086018652908152632132b0b960e11b8183015261016084015283518085019094529083526210d85d60ea1b908301526101808101919091526200049d90604590600d620011d2565b506040805160e081018252600660a0820190815265139bdc9b585b60d21b60c0830152815281518083018352600580825264416e67727960d81b6020838101919091528084019290925283518085018552600381526214d85960ea1b81840152838501528351808501855281815264536d696c6560d81b818401526060840152835180850190945280845264155c1cd95d60da1b9184019190915260808201929092526200054f916052919062001217565b50604080516101a08101825260046101608201818152632437b93760e11b6101808401528252825180840184526008815267576869736b65727360c01b6020828101919091528084019190915283518085018552600c81526b15da1a5cdad95c9cc819985d60a21b818301528385015283518085018552600680825265466c7566667960d01b82840152606085019190915284518086018652600d81526c2bb434b9b5b2b939903a3434b760991b818401526080850152845180860186528181526553717561726560d01b8184015260a08501528451808601865260078152662430b6b9ba32b960c91b8184015260c08501528451808601865290815265139bdc9b585b60d21b8183015260e084015283518085018552600a815269437269636574696e616560b01b8183015261010084015283518085018552918252634e616a6160e01b82820152610120830191909152825180840190935260058352640506c756d760dc1b90830152610140810191909152620006d390605790600b6200125c565b506040518061016001604052806040518060400160405280600381526020016214da5d60ea1b815250815260200160405180604001604052806005815260200164447265737360d81b81525081526020016040518060400160405280600581526020016414dd185b9960da1b8152508152602001604051806040016040528060098152602001680487564646c652075760bc1b815250815260200160405180604001604052806006815260200165466565626c6560d01b81525081526020016040518060400160405280600481526020016329ba30b960e11b815250815260200160405180604001604052806007815260200166436c6f7468657360c81b8152508152602001604051806040016040528060068152602001655374726f6e6760d01b81525081526020016040518060400160405280600581526020016414dc5d585d60da1b81525081526020016040518060400160405280600481526020016348756c6b60e01b8152508152602001604051806040016040528060098152602001684c6f6e67206c65677360b81b815250815250606290600b620008799291906200125c565b5060405180602001604052806040518060e0016040528060ac81526020016200905960ac91399052620008b190606d906001620012a1565b50604080516102a0810190915260c96101a0820181815282916200836f6101c0840139815260200160405180610100016040528060d8815260200162008bf460d8913981526020016040518060e0016040528060b5815260200162009bca60b5913981526020016040518060e0016040528060bb81526020016200882260bb913981526020016040518060e0016040528060be81526020016200974a60be9139815260200160405180610100016040528060c781526020016200843860c7913981526020016040518060e0016040528060bd81526020016200940460bd913981526020016040518060e0016040528060b981526020016200934b60b9913981526020016040518060e0016040528060b181526020016200980860b1913981526020016040518060e0016040528060b0815260200162008ec260b0913981526020016040518060e0016040528060b181526020016200877160b1913981526020016040518060e0016040528060ae815260200162009a4160ae913981526020016040518060e0016040528060b6815260200162009d3c60b69139905262000a5c90606e90600d620012f4565b5060408051610180810190915260a860a08201818152829162008d7060c084013981526020016040518060e0016040528060a781526020016200860f60a7913981526020016040518060e0016040528060aa815260200162009edd60aa913981526020016040518060e0016040528060a4815260200162008a6160a4913981526020016040518060e0016040528060ac8152602001620089b560ac9139905262000b0b90607b90600562001339565b5060408051610240810190915260bd6101608201818152829162009c7f61018084013981526020016040518060e0016040528060b8815260200162009f8760b8913981526020016040518060e0016040528060b38152602001620095ae60b3913981526020016040518060e0016040528060a4815260200162008ccc60a4913981526020016040518060e0016040528060a98152602001620092a260a9913981526020016040518060c00160405280609281526020016200912f6092913981526020016040518060e0016040528060ad8152602001620098b960ad913981526020016040518060e0016040528060aa815260200162008e1860aa913981526020016040518060e0016040528060b081526020016200890560b0913981526020016040518060e0016040528060a98152602001620081f460a9913981526020016040518060e0016040528060bb8152602001620086b660bb9139905262000c7690608090600b6200137e565b50604080516102a0810190915261010261016082018181528291620080f2610180840139815260200160405180610120016040528060ed8152602001620094c160ed9139815260200160405180610120016040528060ef815260200162008b0560ef9139815260200160405180610120016040528060e981526020016200966160e99139815260200160405180610120016040528060eb815260200162009df260eb9139815260200160405180610120016040528060e7815260200162008f7260e79139815260200160405180610100016040528060db81526020016200996660db9139815260200160405180610100016040528060d281526020016200829d60d29139815260200160405180610100016040528060da8152602001620084ff60da9139815260200160405180610120016040528060e18152602001620091c160e19139815260200160405180610100016040528060db815260200162009aef60db9139905262000dec90608b90600b6200137e565b5060405162000dfb90620013c3565b604051809103906000f08015801562000e18573d6000803e3d6000fd5b50609680546001600160a01b0319166001600160a01b0392909216919091179055600060978190556361cf998160b35560b45534801562000e5857600080fd5b506040518060400160405280600881526020016754616d61676f676960c01b81525060405180604001604052806004815260200163544d474760e01b81525062000eb162000eab6200100f60201b60201c565b62001013565b815162000ec6906003906020850190620013d1565b50805162000edc906004906020840190620013d1565b506001808155600955505060006098556107d0609955610721609a5560ac805462ff00001916905560408051606081018252600881526028602082015260789181019190915262000f3290609b906003620010fe565b506040805160608101825260068152601e6020820152605a9181019190915262000f6190609e906003620010fe565b50604080516060810182526004815260146020820152603c9181019190915262000f909060a1906003620010fe565b50604080516060810182526009815260036020820181905260019282019290925262000fc09160a49190620010fe565b506040805160a08101825260008152600a6020820152601491810191909152601e60608201526028608082015262000ffd9060a790600562001168565b5060ac805461ffff1916905562001526565b3390565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82600a810192821562001099579160200282015b8281111562001099578251829060ff1690559160200191906001019062001077565b50620010a79291506200144e565b5090565b8260038101928215620010f0579160200282015b82811115620010f05782518051620010df918491602090910190620013d1565b5091602001919060010190620010bf565b50620010a792915062001465565b826003810192821562001099579160200282018281111562001099578251829060ff1690559160200191906001019062001077565b82600d810192821562001099579160200282018281111562001099578251829060ff1690559160200191906001019062001077565b826005810192821562001099579160200282018281111562001099578251829060ff1690559160200191906001019062001077565b82600b810192821562001099579160200282018281111562001099578251829060ff1690559160200191906001019062001077565b82600d8101928215620010f0579160200282015b82811115620010f0578251805162001206918491602090910190620013d1565b5091602001919060010190620011e6565b8260058101928215620010f0579160200282015b82811115620010f057825180516200124b918491602090910190620013d1565b50916020019190600101906200122b565b82600b8101928215620010f0579160200282015b82811115620010f0578251805162001290918491602090910190620013d1565b509160200191906001019062001270565b8260018101928215620012e6579160200282015b82811115620012e65782518051620012d5918491602090910190620013d1565b5091602001919060010190620012b5565b50620010a792915062001486565b82600d8101928215620012e6579160200282015b82811115620012e6578251805162001328918491602090910190620013d1565b509160200191906001019062001308565b8260058101928215620012e6579160200282015b82811115620012e657825180516200136d918491602090910190620013d1565b50916020019190600101906200134d565b82600b8101928215620012e6579160200282015b82811115620012e65782518051620013b2918491602090910190620013d1565b509160200191906001019062001392565b61154e8062006ba483390190565b828054620013df90620014e9565b90600052602060002090601f01602090048101928262001403576000855562001099565b82601f106200141e57805160ff191683800117855562001099565b8280016001018555821562001099579182015b828111156200109957825182559160200191906001019062001431565b5b80821115620010a757600081556001016200144f565b80821115620010a75760006200147c8282620014a7565b5060010162001465565b80821115620010a75760006200149d8282620014a7565b5060010162001486565b508054620014b590620014e9565b6000825580601f10620014c6575050565b601f016020900490600052602060002090810190620014e691906200144e565b50565b600181811c90821680620014fe57607f821691505b602082108114156200152057634e487b7160e01b600052602260045260246000fd5b50919050565b61566e80620015366000396000f3fe6080604052600436106102885760003560e01c806370a082311161015a578063b88d4fde116100c1578063e985e9c51161007a578063e985e9c514610841578063ebd799cc1461088a578063ebf6e91d146108aa578063f2fde38b146108ca578063f59dfdfb146108ea578063fe55932a1461090a57600080fd5b8063b88d4fde1461077b578063c23c863b1461079b578063c87b56dd146107cb578063ca9c4b33146107eb578063d3a2da38146107f3578063df33fa311461082e57600080fd5b806391b7f5ed1161011357806391b7f5ed146106b657806395d89b41146106d65780639b993a1a146106eb578063a22cb4651461071b578063a22d58231461073b578063b6d225511461075b57600080fd5b806370a08231146105ba578063715018a6146105da5780637908213d146105ef57806379502c55146106205780638462151c1461066b5780638da5cb5b1461069857600080fd5b806335b34ca2116101fe5780635d186c9f116101b75780635d186c9f1461051d57806361fd3f62146105325780636352211e1461053a57806366d38ba91461055a5780636840690b1461057a5780636898f82b1461059a57600080fd5b806335b34ca2146104435780633cd434aa1461047357806341b3ba3d1461048857806342842e0e146104a8578063439bbfd2146104c85780635a353cd3146104e857600080fd5b806309a3849a1161025057806309a3849a1461035e5780630ea61c471461037e57806318160ddd146103c65780631c19c215146103ed5780631d80009a1461040d57806323b872dd1461042357600080fd5b806301ffc9a71461028d57806306fdde03146102c2578063081812fc146102e457806308a337331461031c578063095ea7b31461033e575b600080fd5b34801561029957600080fd5b506102ad6102a8366004614385565b61092a565b60405190151581526020015b60405180910390f35b3480156102ce57600080fd5b506102d761097c565b6040516102b99190615374565b3480156102f057600080fd5b506103046102ff36600461436c565b610a0e565b6040516001600160a01b0390911681526020016102b9565b34801561032857600080fd5b5061033c610337366004614328565b610a52565b005b34801561034a57600080fd5b5061033c610359366004614289565b610a6b565b34801561036a57600080fd5b5061033c61037936600461434a565b610b0b565b34801561038a57600080fd5b5061039e61039936600461436c565b610b20565b60408051948552921515602085015290151591830191909152151560608201526080016102b9565b3480156103d257600080fd5b5060025460015403600019015b6040519081526020016102b9565b3480156103f957600080fd5b5061033c61040836600461436c565b610f23565b34801561041957600080fd5b506103df60975481565b34801561042f57600080fd5b5061033c61043e366004614195565b61105b565b34801561044f57600080fd5b506102ad61045e366004614147565b60b26020526000908152604090205460ff1681565b34801561047f57600080fd5b5061033c6111ec565b34801561049457600080fd5b5061033c6104a336600461436c565b611205565b3480156104b457600080fd5b5061033c6104c3366004614195565b611212565b3480156104d457600080fd5b5061033c6104e3366004614328565b611232565b3480156104f457600080fd5b5061050861050336600461436c565b611247565b604080519283526020830191909152016102b9565b34801561052957600080fd5b5061033c61156b565b61033c611582565b34801561054657600080fd5b5061030461055536600461436c565b6116c8565b34801561056657600080fd5b5061033c61057536600461436c565b6116d3565b34801561058657600080fd5b506102ad61059536600461436c565b611715565b3480156105a657600080fd5b5061033c6105b536600461436c565b611a82565b3480156105c657600080fd5b506103df6105d5366004614147565b611b30565b3480156105e657600080fd5b5061033c611b7f565b3480156105fb57600080fd5b5061060f61060a36600461436c565b611b93565b6040516102b9959493929190615387565b34801561062c57600080fd5b50609854609954609a5460ac546106599392919060ff808216916101008104821691620100009091041686565b6040516102b99695949392919061542e565b34801561067757600080fd5b5061068b610686366004614147565b611c49565b6040516102b9919061533c565b3480156106a457600080fd5b506000546001600160a01b0316610304565b3480156106c257600080fd5b5061033c6106d136600461436c565b611d59565b3480156106e257600080fd5b506102d7611d66565b3480156106f757600080fd5b506102ad61070636600461436c565b60af6020526000908152604090205460ff1681565b34801561072757600080fd5b5061033c61073636600461424d565b611d75565b34801561074757600080fd5b5061033c610756366004614328565b611e0b565b34801561076757600080fd5b5061050861077636600461436c565b611e20565b34801561078757600080fd5b5061033c6107963660046141d1565b612095565b3480156107a757600080fd5b506102ad6107b6366004614147565b60b16020526000908152604090205460ff1681565b3480156107d757600080fd5b506102d76107e636600461436c565b6120df565b61033c6120ea565b3480156107ff57600080fd5b506102ad61080e3660046143bf565b805160208183018101805160b08252928201919093012091525460ff1681565b61033c61083c3660046142b3565b612222565b34801561084d57600080fd5b506102ad61085c366004614162565b6001600160a01b03918216600090815260086020908152604080832093909416825291909152205460ff1690565b34801561089657600080fd5b5061033c6108a5366004614328565b612410565b3480156108b657600080fd5b5061033c6108c536600461436c565b612425565b3480156108d657600080fd5b5061033c6108e5366004614147565b6124cb565b3480156108f657600080fd5b5061033c61090536600461436c565b612544565b34801561091657600080fd5b5061033c610925366004614421565b6125ea565b60006301ffc9a760e01b6001600160e01b03198316148061095b57506380ac58cd60e01b6001600160e01b03198316145b806109765750635b5e139f60e01b6001600160e01b03198316145b92915050565b60606003805461098b90615510565b80601f01602080910402602001604051908101604052809291908181526020018280546109b790615510565b8015610a045780601f106109d957610100808354040283529160200191610a04565b820191906000526020600020905b8154815290600101906020018083116109e757829003601f168201915b5050505050905090565b6000610a19826127e4565b610a36576040516333d1c03960e21b815260040160405180910390fd5b506000908152600760205260409020546001600160a01b031690565b610a5a612819565b610a6760a4826003613f53565b5050565b6000610a76826116c8565b9050336001600160a01b03821614610aaf57610a92813361085c565b610aaf576040516367d9dca160e11b815260040160405180910390fd5b60008281526007602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b610b13612819565b610a6760a7826005613f91565b60ac54600090819081908190610100900460ff16610b595760405162461bcd60e51b8152600401610b50906153e8565b60405180910390fd5b609954859081118015610b6e5750609a548111155b610b8a5760405162461bcd60e51b8152600401610b50906153be565b600086815260ae6020526040808220815160a081019092528054429392919082908290610bb690615510565b80601f0160208091040260200160405190810160405280929190818152602001828054610be290615510565b8015610c2f5780601f10610c0457610100808354040283529160200191610c2f565b820191906000526020600020905b815481529060010190602001808311610c1257829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b8152600401610cb4929190918252602082015260400190565b60206040518083038186803b158015610ccc57600080fd5b505afa158015610ce0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d049190614408565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b891610d48918890600401918252602082015260400190565b60206040518083038186803b158015610d6057600080fd5b505afa158015610d74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d989190614408565b905060008360600151600014610dc957603c846060015186610dba91906154cd565b610dc4919061549a565b610dcc565b60005b9050600060a18101548211610df35760a460005b0154610dec90836154ae565b9050610e27565b60a254821015610e065760a46001610de0565b60a354821015610e195760a46002610de0565b610e248260006154ae565b90505b6000610e356106868e6116c8565b90506000806000805b8451811015610ef1576000858281518110610e5b57610e5b6155b6565b602002602001015190506098600101548111610ede57600081815260ad602052604081205490600a610e8d8184615560565b600a8110610e9d57610e9d6155b6565b0154905080610eb35760009b5060019650610edb565b8060011415610ec95760009a5060019550610edb565b8060021415610edb5760009850600194505b50505b5080610ee981615545565b915050610e3e565b50600085610eff898b615482565b610f099190615482565b9f50929d50909b5099505050505050505050509193509193565b8033610f2e826116c8565b6001600160a01b031614610f805760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610b50565b60ac54610100900460ff16610fa75760405162461bcd60e51b8152600401610b50906153e8565b609954829081118015610fbc5750609a548111155b610fd85760405162461bcd60e51b8152600401610b50906153be565b600083815260af602052604090205460ff16156110275760405162461bcd60e51b815260206004820152600d60248201526c4e6f7420617661696c61626c6560981b6044820152606401610b50565b61103083612873565b600093845260ad602090815260408086209290925560af9052909220805460ff191660011790555050565b6000611066826128cc565b9050836001600160a01b0316816001600160a01b0316146110995760405162a1148160e81b815260040160405180910390fd5b60008281526007602052604090208054338082146001600160a01b038816909114176110e6576110c9863361085c565b6110e657604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b03851661110d57604051633a954ecd60e21b815260040160405180910390fd5b801561111857600082555b6001600160a01b038681166000908152600660205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260056020526040902055600160e11b83166111a357600184016000818152600560205260409020546111a15760015481146111a15760008181526005602052604090208490555b505b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b6111f4612819565b60ac805461ff001916610100179055565b61120d612819565b609755565b61122d83838360405180602001604052806000815250612095565b505050565b61123a612819565b610a67609e826003613f53565b60ac546000908190610100900460ff166112735760405162461bcd60e51b8152600401610b50906153e8565b6099548390811180156112885750609a548111155b6112a45760405162461bcd60e51b8152600401610b50906153be565b600084815260ae6020526040808220815160a0810190925280544293929190829082906112d090615510565b80601f01602080910402602001604051908101604052809291908181526020018280546112fc90615510565b80156113495780601f1061131e57610100808354040283529160200191611349565b820191906000526020600020905b81548152906001019060200180831161132c57829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b81526004016113ce929190918252602082015260400190565b60206040518083038186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e9190614408565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b891611462918890600401918252602082015260400190565b60206040518083038186803b15801561147a57600080fd5b505afa15801561148e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b29190614408565b905060006114c26106868a6116c8565b905060005b815181101561155c5760008282815181106114e4576114e46155b6565b60200260200101519050609860010154811161154957600081815260ad602052604081205490600a6115168184615560565b600a8110611526576115266155b6565b01549050806115385760009650611546565b806001141561154657600095505b50505b508061155481615545565b9150506114c7565b50919650945050505050915091565b611573612819565b60ac805460ff19166001179055565b600160ac5462010000900460ff1660038111156115a1576115a16155a0565b146115ee5760405162461bcd60e51b815260206004820152601860248201527f4e6f7420696e20737461676520746f206275792070726f7000000000000000006044820152606401610b50565b60995460015460001901106116355760405162461bcd60e51b815260206004820152600d60248201526c139bc81c1c9bdc1cc81b19599d609a1b6044820152606401610b50565b33600090815260b1602052604090205460ff16156116655760405162461bcd60e51b8152600401610b509061540c565b60006116746001546000190190565b61167f906001615482565b9050600061168c82612873565b600083815260ad6020526040902081905590506116aa33600161293c565b505033600090815260b160205260409020805460ff19166001179055565b6000610976826128cc565b6116db612819565b8060038111156116ed576116ed6155a0565b60ac805462ff000019166201000083600381111561170d5761170d6155a0565b021790555050565b6000816098600101548111801561172e5750609a548111155b61174a5760405162461bcd60e51b8152600401610b50906153be565b600083815260ae6020526040808220815160a0810190925280548290829061177190615510565b80601f016020809104026020016040519081016040528092919081815260200182805461179d90615510565b80156117ea5780601f106117bf576101008083540402835291602001916117ea565b820191906000526020600020905b8154815290600101906020018083116117cd57829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000429050600060ad600087815260200190815260200160002054905060006301e133808261184c9190615560565b60965460808601519192506001600160a01b0316906365c7284090611872908490615482565b6040518263ffffffff1660e01b815260040161189091815260200190565b60206040518083038186803b1580156118a857600080fd5b505afa1580156118bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e09190614408565b6096546040516301971ca160e61b8152600481018690526001600160a01b03909116906365c728409060240160206040518083038186803b15801561192457600080fd5b505afa158015611938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195c9190614408565b148015611a75575060965460808501516001600160a01b039091169063a324ad2490611989908490615482565b6040518263ffffffff1660e01b81526004016119a791815260200190565b60206040518083038186803b1580156119bf57600080fd5b505afa1580156119d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f79190614408565b6096546040516328c92b4960e21b8152600481018690526001600160a01b039091169063a324ad249060240160206040518083038186803b158015611a3b57600080fd5b505afa158015611a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a739190614408565b145b9550505050505b50919050565b60ac54610100900460ff16611aa95760405162461bcd60e51b8152600401610b50906153e8565b609954819081118015611abe5750609a548111155b611ada5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600290910155815184815233918101919091527fd0017656a8c92d10b2fa3a77fa3c1e8e4c28817e89311616b8eed8e68f68a95091015b60405180910390a15050565b60006001600160a01b038216611b59576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526006602052604090205467ffffffffffffffff1690565b611b87612819565b611b916000612956565b565b60ae60205260009081526040902080548190611bae90615510565b80601f0160208091040260200160405190810160405280929190818152602001828054611bda90615510565b8015611c275780601f10611bfc57610100808354040283529160200191611c27565b820191906000526020600020905b815481529060010190602001808311611c0a57829003601f168201915b5050505050908060010154908060020154908060030154908060040154905085565b60606000806000611c5985611b30565b905060008167ffffffffffffffff811115611c7657611c766155cc565b604051908082528060200260200182016040528015611c9f578160200160208202803683370190505b509050611ccc60408051608081018252600080825260208201819052918101829052606081019190915290565b60015b838614611d4d57611cdf816129a6565b9150816040015115611cf057611d45565b81516001600160a01b031615611d0557815194505b876001600160a01b0316856001600160a01b03161415611d455780838780600101985081518110611d3857611d386155b6565b6020026020010181815250505b600101611ccf565b50909695505050505050565b611d61612819565b609855565b60606004805461098b90615510565b6001600160a01b038216331415611d9f5760405163b06307db60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b611e13612819565b610a67609b826003613f53565b6000808260986001015481118015611e3a5750609a548111155b611e565760405162461bcd60e51b8152600401610b50906153be565b600084815260ae6020526040808220815160a08101909252805482908290611e7d90615510565b80601f0160208091040260200160405190810160405280929190818152602001828054611ea990615510565b8015611ef65780601f10611ecb57610100808354040283529160200191611ef6565b820191906000526020600020905b815481529060010190602001808311611ed957829003601f168201915b505050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250509050600060ad600087815260200190815260200160002054905060006301e1338082611f539190615560565b60965460808501519192506000916001600160a01b039091169063a324ad2490611f7e908590615482565b6040518263ffffffff1660e01b8152600401611f9c91815260200190565b60206040518083038186803b158015611fb457600080fd5b505afa158015611fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fec9190614408565b60965460808601519192506000916001600160a01b03909116906365c7284090612017908690615482565b6040518263ffffffff1660e01b815260040161203591815260200190565b60206040518083038186803b15801561204d57600080fd5b505afa158015612061573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120859190614408565b9197509095505050505050915091565b6120a084848461105b565b6001600160a01b0383163b156120d9576120bc84848484612a25565b6120d9576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b606061097682612b1d565b600360ac5462010000900460ff166003811115612109576121096155a0565b146121565760405162461bcd60e51b815260206004820152601960248201527f4e6f7420696e20737461676520746f206d696e7420544d4747000000000000006044820152606401610b50565b609a54600154600019011061219b5760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610b50565b33600090815260b2602052604090205460ff16156121cb5760405162461bcd60e51b8152600401610b509061540c565b60985434906121db9060016154ae565b111561221a5760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610b50565b611b91612bec565b600260ac5462010000900460ff166003811115612241576122416155a0565b1461228e5760405162461bcd60e51b815260206004820181905260248201527f4e6f7420696e20737461676520746f206d696e74206d65726b6c6520544d47476044820152606401610b50565b609a5460015460001901106122d35760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610b50565b33600090815260b2602052604090205460ff16156123035760405162461bcd60e51b8152600401610b509061540c565b60985434906123139060016154ae565b11156123525760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610b50565b6040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506123cc838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506097549150849050612d7e565b6124085760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610b50565b61122d612bec565b612418612819565b610a6760a1826003613f53565b60ac54610100900460ff1661244c5760405162461bcd60e51b8152600401610b50906153e8565b6099548190811180156124615750609a548111155b61247d5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600390910155815184815233918101919091527fbae6551c0ddf25aa6805100ecbdc4535f2933a14d7ebafe9fab66af752e232ec9101611b24565b6124d3612819565b6001600160a01b0381166125385760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b50565b61254181612956565b50565b60ac54610100900460ff1661256b5760405162461bcd60e51b8152600401610b50906153e8565b6099548190811180156125805750609a548111155b61259c5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600190910155815184815233918101919091527fd73f65a9b0fee6c2e3e08fd03cb4800137b36882554a7211fe8ce842b3d4f4fe9101611b24565b82336125f5826116c8565b6001600160a01b0316146126475760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610b50565b60ac54610100900460ff1661266e5760405162461bcd60e51b8152600401610b50906153e8565b6099548490811180156126835750609a548111155b61269f5760405162461bcd60e51b8152600401610b50906153be565b60b084846040516126b19291906145f3565b9081526040519081900360200190205460ff16156126fe5760405162461bcd60e51b815260206004820152600a60248201526913985b5948195e1a5cdd60b21b6044820152606401610b50565b600061273f85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d9492505050565b90506001811180156127515750601281105b61278e5760405162461bcd60e51b815260206004820152600e60248201526d4e6f742076616c6964206e616d6560901b6044820152606401610b50565b600086815260ae602052604090206127a7908686613fbe565b50600160b086866040516127bc9291906145f3565b908152604051908190036020019020805491151560ff19909216919091179055505050505050565b6000816001111580156127f8575060015482105b8015610976575050600090815260056020526040902054600160e01b161590565b6000546001600160a01b03163314611b915760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b50565b6000806128816001436154cd565b6040805191406020830152810184905233606090811b6bffffffffffffffffffffffff19169082015260740160408051601f1981840301815291905280516020909101209392505050565b600081806001116129235760015481101561292357600081815260056020526040902054600160e01b8116612921575b8061291a5750600019016000818152600560205260409020546128fc565b9392505050565b505b604051636f96cda160e11b815260040160405180910390fd5b610a67828260405180602001604052806000815250612ed1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60408051608081018252600080825260208201819052918101829052606081019190915260008281526005602052604090205461097690604080516080810182526001600160a01b038316815260a083901c67ffffffffffffffff166020820152600160e01b831615159181019190915260e89190911c606082015290565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a0290612a5a903390899088908890600401615309565b602060405180830381600087803b158015612a7457600080fd5b505af1925050508015612aa4575060408051601f3d908101601f19168201909252612aa1918101906143a2565b60015b612aff573d808015612ad2576040519150601f19603f3d011682016040523d82523d6000602084013e612ad7565b606091505b508051612af7576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490505b949350505050565b60608160018110158015612b375750600154600019018111155b612b725760405162461bcd60e51b815260206004820152600c60248201526b139bdd081d985b1a59081a5960a21b6044820152606401610b50565b609954600090841115612ba55760ac54610100900460ff16612b9c57612b9784612f3e565b612bc1565b612b9784612feb565b60ac5460ff16612bb857612b978461313a565b612bc18461315a565b905080604051602001612bd49190615168565b60405160208183030381529060405292505050919050565b6000612bfb6001546000190190565b612c06906001615482565b905060b45460051415612ca357600060b45560965460b354604051631c85d48f60e21b81526004810191909152600160248201526001600160a01b0390911690637217523c9060440160206040518083038186803b158015612c6757600080fd5b505afa158015612c7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9f9190614408565b60b3555b6040805160c081018252600060a082018181528252426020808401829052838501919091526060830182905260b354608084015284825260ae81529290208151805192938493612cf69284920190614031565b5060208201516001820155604082015160028201556060820151600382015560809091015160049091015560b48054906000612d3183615545565b91905055506000612d4183612873565b600084815260ad602052604090208190559050612d5f33600161293c565b505033600090815260b260205260409020805460ff1916600117905550565b600082612d8b85846132ff565b14949350505050565b600080825b8051821015612eca576007818381518110612db657612db66155b6565b01602001516001600160f81b031990811690911c16612de157612dda600183615482565b9150612eb8565b8051600360f91b90600590839085908110612dfe57612dfe6155b6565b01602001516001600160f81b031990811690911c161415612e2457612dda600283615482565b8051600760f91b90600490839085908110612e4157612e416155b6565b01602001516001600160f81b031990811690911c161415612e6757612dda600383615482565b8051600f60f91b90600390839085908110612e8457612e846155b6565b01602001516001600160f81b031990811690911c161415612eaa57612dda600483615482565b612eb5600183615482565b91505b82612ec281615545565b935050612d99565b5050919050565b612edb838361334c565b6001600160a01b0383163b1561122d576001548281035b612f056000868380600101945086612a25565b612f22576040516368d2bf6b60e11b815260040160405180910390fd5b818110612ef2578160015414612f3757600080fd5b5050505050565b6060600080612f4c84611e20565b600086815260ad6020526040812054929450909250612fe1612f6d87613443565b612f7686613443565b612f7f86613443565b612f8888613443565b612f9188613443565b612fb8601a612fa160038b615560565b60038110612fb157612fb16155b6565b0154613443565b604051602001612fcd96959493929190614e5d565b604051602081830303815290604052613541565b9695505050505050565b6060600080600080612ffc86610b20565b935093509350935060008061301088611247565b91509150600061301f89611715565b9050600086801561302d5750855b80156130365750845b8061303e5750815b61304957600061304c565b60015b90506000613059896136a7565b905060006040518060c001604052808d815260200160ad60008f81526020019081526020016000205481526020018781526020018681526020018b8152602001841515815250905060006130c160ad60008f8152602001908152602001600020548486613707565b905060006130ce83613ae9565b6130d784613c7b565b6130e085613cc1565b6130e986613d6e565b6130fa6130f587613da7565b613541565b60405160200161310e959493929190614689565b604051602081830303815290604052905061312881613541565b9e9d5050505050505050505050505050565b6060600061291a61314a84613443565b604051602001612fcd9190614d2b565b600081815260ad6020526040812054606091600a6131788184615560565b600a8110613188576131886155b6565b015490506000601782600381106131a1576131a16155b6565b0180546131ad90615510565b80601f01602080910402602001604051908101604052809291908181526020018280546131d990615510565b80156132265780601f106131fb57610100808354040283529160200191613226565b820191906000526020600020905b81548152906001019060200180831161320957829003601f168201915b50505050509050600060148360038110613242576132426155b6565b01805461324e90615510565b80601f016020809104026020016040519081016040528092919081815260200182805461327a90615510565b80156132c75780601f1061329c576101008083540402835291602001916132c7565b820191906000526020600020905b8154815290600101906020018083116132aa57829003601f168201915b5050505050905060006132f46132dc88613443565b83858586604051602001612fcd959493929190614b88565b979650505050505050565b600081815b84518110156133445761333082868381518110613323576133236155b6565b6020026020010151613dd0565b91508061333c81615545565b915050613304565b509392505050565b6001548161336d5760405163b562e8dd60e01b815260040160405180910390fd5b6001600160a01b03831660008181526006602090815260408083208054680100000000000000018802019055848352600590915281206001851460e11b4260a01b178317905582840190839083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600183015b81811461341c57808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a46001016133e4565b508161343a57604051622e076360e81b815260040160405180910390fd5b60015550505050565b6060816134675750506040805180820190915260018152600360fc1b602082015290565b8160005b8115613491578061347b81615545565b915061348a9050600a8361549a565b915061346b565b60008167ffffffffffffffff8111156134ac576134ac6155cc565b6040519080825280601f01601f1916602001820160405280156134d6576020820181803683370190505b5090505b8415612b15576134eb6001836154cd565b91506134f8600a86615560565b613503906030615482565b60f81b818381518110613518576135186155b6565b60200101906001600160f81b031916908160001a90535061353a600a8661549a565b94506134da565b606081516000141561356157505060408051602081019091526000815290565b60006040518060600160405280604081526020016155f960409139905060006003845160026135909190615482565b61359a919061549a565b6135a59060046154ae565b905060006135b4826020615482565b67ffffffffffffffff8111156135cc576135cc6155cc565b6040519080825280601f01601f1916602001820160405280156135f6576020820181803683370190505b509050818152600183018586518101602084015b81831015613662576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f811685015182535060010161360a565b60038951066001811461367c576002811461368d57613699565b613d3d60f01b600119830152613699565b603d60f81b6000198301525b509398975050505050505050565b60a75460009082116136c057602a60035b015492915050565b60a8548210156136d357602a60006136b8565b60a9548210156136e657602a60016136b8565b60aa548210156136f957602a60026136b8565b602a60046136b8565b919050565b60606000608b600b61371a60048861549a565b6137249190615560565b600b8110613734576137346155b6565b01805461374090615510565b80601f016020809104026020016040519081016040528092919081815260200182805461376c90615510565b80156137b95780601f1061378e576101008083540402835291602001916137b9565b820191906000526020600020905b81548152906001019060200180831161379c57829003601f168201915b5050505050905060006080600b6003886137d3919061549a565b6137dd9190615560565b600b81106137ed576137ed6155b6565b0180546137f990615510565b80601f016020809104026020016040519081016040528092919081815260200182805461382590615510565b80156138725780601f1061384757610100808354040283529160200191613872565b820191906000526020600020905b81548152906001019060200180831161385557829003601f168201915b505050505090506000606e600d60028961388c919061549a565b6138969190615560565b600d81106138a6576138a66155b6565b0180546138b290615510565b80601f01602080910402602001604051908101604052809291908181526020018280546138de90615510565b801561392b5780601f106139005761010080835404028352916020019161392b565b820191906000526020600020905b81548152906001019060200180831161390e57829003601f168201915b505050505090506000607b8760058110613947576139476155b6565b01805461395390615510565b80601f016020809104026020016040519081016040528092919081815260200182805461397f90615510565b80156139cc5780601f106139a1576101008083540402835291602001916139cc565b820191906000526020600020905b8154815290600101906020018083116139af57829003601f168201915b5050505050905060006139de85613dfc565b6139e785613dfc565b6139f084613dfc565b6139f986613dfc565b604051602001613a0c9493929190614632565b60405160208183030381529060405290508615613add5780613aba606d6000018054613a3790615510565b80601f0160208091040260200160405190810160405280929190818152602001828054613a6390615510565b8015613ab05780601f10613a8557610100808354040283529160200191613ab0565b820191906000526020600020905b815481529060010190602001808311613a9357829003601f168201915b5050505050613dfc565b604051602001613acb929190614603565b60405160208183030381529060405290505b98975050505050505050565b6060600080613afb8460000151611e20565b91509150600060ae6000866000015181526020019081526020016000206040518060a0016040529081600082018054613b3390615510565b80601f0160208091040260200160405190810160405280929190818152602001828054613b5f90615510565b8015613bac5780601f10613b8157610100808354040283529160200191613bac565b820191906000526020600020905b815481529060010190602001808311613b8f57829003601f168201915b50505050508152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006001613bf08360000151612d94565b11613c0a5760405180602001604052806000815250613c2c565b8151604051613c1c9190602001614842565b6040516020818303038152906040525b905080613c3c8760000151613443565b613c4586613443565b613c4e86613443565b604051602001613c61949392919061501c565b604051602081830303815290604052945050505050919050565b60606000613c8c8360400151613443565b613c998460600151613443565b604051602001613caa92919061493d565b60408051601f198184030181529190529392505050565b606060008260a00151613cee57604051806040016040528060028152602001616e6f60f01b815250613d0b565b6040518060400160405280600381526020016279657360e81b8152505b9050600081613d1d8560800151613443565b613d2686613e17565b613d2f87613e4b565b613d3888613ea3565b613d4189613efb565b604051602001613d5696959493929190614a6d565b60408051601f19818403018152919052949350505050565b6060600080613d808460000151611e20565b91509150613d8d82613443565b613d9682613443565b604051602001612bd49291906150d8565b606081604051602001613dba91906151ad565b6040516020818303038152906040529050919050565b6000818310613dec57600082815260208490526040902061291a565b5060009182526020526040902090565b6060613e0782613541565b604051602001613dba9190614869565b606060006052613e2a84608001516136a7565b60058110613e3a57613e3a6155b6565b01604051602001613caa9190614fdb565b606060006045601d600d60028660200151613e66919061549a565b613e709190615560565b600d8110613e8057613e806155b6565b0154600d8110613e9257613e926155b6565b01604051602001613caa9190614a1e565b606060006057602f600b60038660200151613ebe919061549a565b613ec89190615560565b600b8110613ed857613ed86155b6565b0154600b8110613eea57613eea6155b6565b01604051602001613caa91906152cc565b606060006062603a600b60048660200151613f16919061549a565b613f209190615560565b600b8110613f3057613f306155b6565b0154600b8110613f4257613f426155b6565b01604051602001613caa919061512b565b8260038101928215613f81579160200282015b82811115613f81578235825591602001919060010190613f66565b50613f8d9291506140a5565b5090565b8260058101928215613f815791602002820182811115613f81578235825591602001919060010190613f66565b828054613fca90615510565b90600052602060002090601f016020900481019282613fec5760008555613f81565b82601f106140055782800160ff19823516178555613f81565b82800160010185558215613f815791820182811115613f81578235825591602001919060010190613f66565b82805461403d90615510565b90600052602060002090601f01602090048101928261405f5760008555613f81565b82601f1061407857805160ff1916838001178555613f81565b82800160010185558215613f81579182015b82811115613f8157825182559160200191906001019061408a565b5b80821115613f8d57600081556001016140a6565b600067ffffffffffffffff808411156140d5576140d56155cc565b604051601f8501601f19908116603f011681019082821181831017156140fd576140fd6155cc565b8160405280935085815286868601111561411657600080fd5b858560208301376000602087830101525050509392505050565b80356001600160a01b038116811461370257600080fd5b60006020828403121561415957600080fd5b61291a82614130565b6000806040838503121561417557600080fd5b61417e83614130565b915061418c60208401614130565b90509250929050565b6000806000606084860312156141aa57600080fd5b6141b384614130565b92506141c160208501614130565b9150604084013590509250925092565b600080600080608085870312156141e757600080fd5b6141f085614130565b93506141fe60208601614130565b925060408501359150606085013567ffffffffffffffff81111561422157600080fd5b8501601f8101871361423257600080fd5b614241878235602084016140ba565b91505092959194509250565b6000806040838503121561426057600080fd5b61426983614130565b91506020830135801515811461427e57600080fd5b809150509250929050565b6000806040838503121561429c57600080fd5b6142a583614130565b946020939093013593505050565b600080602083850312156142c657600080fd5b823567ffffffffffffffff808211156142de57600080fd5b818501915085601f8301126142f257600080fd5b81358181111561430157600080fd5b8660208260051b850101111561431657600080fd5b60209290920196919550909350505050565b60006060828403121561433a57600080fd5b82606083011115611a7c57600080fd5b600060a0828403121561435c57600080fd5b8260a083011115611a7c57600080fd5b60006020828403121561437e57600080fd5b5035919050565b60006020828403121561439757600080fd5b813561291a816155e2565b6000602082840312156143b457600080fd5b815161291a816155e2565b6000602082840312156143d157600080fd5b813567ffffffffffffffff8111156143e857600080fd5b8201601f810184136143f957600080fd5b612b15848235602084016140ba565b60006020828403121561441a57600080fd5b5051919050565b60008060006040848603121561443657600080fd5b83359250602084013567ffffffffffffffff8082111561445557600080fd5b818601915086601f83011261446957600080fd5b81358181111561447857600080fd5b87602082850101111561448a57600080fd5b6020830194508093505050509250925092565b600081518084526144b58160208601602086016154e4565b601f01601f19169290920160200192915050565b600081516144db8185602086016154e4565b9290920192915050565b8054600090600181811c90808316806144ff57607f831692505b602080841082141561452157634e487b7160e01b600052602260045260246000fd5b818015614535576001811461454657614573565b60ff19861689528489019650614573565b60008881526020902060005b8681101561456b5781548b820152908501908301614552565b505084890196505b50505050505092915050565b7f7b202274726169745f74797065223a202274797065222c202276616c7565223a81526808089c195d1cc89f4b60ba1b602082015260290190565b7f7b202274726169745f74797065223a2022626972746864617465222c20227661815266363ab2911d101160c91b602082015260270190565b8183823760009101908152919050565b600083516146158184602088016154e4565b8351908301906146298183602088016154e4565b01949350505050565b60008551614644818460208a016154e4565b855190830190614658818360208a016154e4565b855191019061466b8183602089016154e4565b845191019061467e8183602088016154e4565b019695505050505050565b6000865161469b818460208b016154e4565b80830190507f226465736372697074696f6e223a202254616d61676f6769206973206120546181527f6d61676f74636869204461707020616e642066756c6c792067656e657261746560208201527f64206f6e2d636861696e2e2054686520636f6e747261637420696e746572616360408201527f74696f6e20616e642074696d652077696c6c206166666563742074686520737460608201527f6174757320616e64207265616374696f6e206f6620746865207065742e20496660808201527f20796f7520636f6c6c656374206f74686572206974656d732c2074686520706560a0820152721d081dda5b1b081cda1bddc81b1bdd9948488b606a1b60c08201526e2261747472696275746573223a205b60881b60d382015286516147c88160e2840160208b016154e4565b6148356148276148216147e96147e360e2868801018c6144c9565b8a6144c9565b7f5d2c22696d616765223a2022646174613a696d6167652f7376672b786d6c3b62815265185cd94d8d0b60d21b602082015260260190565b876144c9565b61227d60f01b815260020190565b9998505050505050505050565b600082516148548184602087016154e4565b6201017960ed1b920191825250600301919050565b7f3c696d61676520783d22302220793d2230222077696474683d2233322220686581527f696768743d2233322220696d6167652d72656e646572696e673d22706978656c60208201527f6174656422207072657365727665417370656374526174696f3d22784d69645960408201527f4d69642220786c696e6b3a687265663d22646174613a696d6167652f706e673b60608201526618985cd94d8d0b60ca1b6080820152600082516149238160878501602087016154e4565b6211179f60e91b6087939091019283015250608a01919050565b7f7b202274726169745f74797065223a202268756e676572222c2022646973706c81527f61795f74797065223a20226e756d626572222c202276616c7565223a2000000060208201526000835161499b81603d8501602088016154e4565b8083019050611f4b60f21b80603d8301527f7b202274726169745f74797065223a2022626f726564222c2022646973706c61603f8301527f795f74797065223a20226e756d626572222c202276616c7565223a2000000000605f8301528451614a0b81607b8501602089016154e4565b607b920191820152607d01949350505050565b7f7b202274726169745f74797065223a2022656172222c202276616c7565223a208152601160f91b60208201526000614a5a60218301846144e5565b62089f4b60ea1b81526003019392505050565b6000614a788261457f565b7f7b202274726169745f74797065223a20226d6173746572222c202276616c7565815263111d101160e11b60208201528851614abb816024840160208d016154e4565b62089f4b60ea1b602492909101918201527f7b202274726169745f74797065223a2022756e68617070696e657373222c202260278201527f646973706c61795f74797065223a20226e756d626572222c202276616c75652260478201526101d160f51b60678201528751614b36816069840160208c016154e4565b611f4b60f21b606992909101918201528651614b5981606b840160208b016154e4565b614b7a614b74614b6e606b848601018a6144c9565b886144c9565b866144c9565b9a9950505050505050505050565b6a7b226e616d65223a20222360a81b81528551600090614baf81600b850160208b016154e4565b6a040a8c2dac2cedeced240560ab1b600b918401918201528651614bda816016840160208b016154e4565b7314911610113232b9b1b934b83a34b7b7111d101160611b601692909101918201528551614c0f81602a840160208a016154e4565b61088b60f21b9101602a8101919091526e2261747472696275746573223a205b60881b602c8201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a603b8201526908089c1c9bdc1cc89f4b60b21b605b8201527f7b202274726169745f74797065223a20227573616765222c202276616c7565226065820152621d101160e91b6085820152613add614d19614b74614cca614cba608886016147e3565b63089f574b60e21b815260040190565b7f22696d616765223a2022697066733a2f2f516d56784344666d7767593270734181527f683777746938614c43796b6b6a3939736e79674751383970327a6b664174662f602082015260400190565b652e676966227d60d01b815260060190565b6a7b226e616d65223a20222360a81b81528151600090614d5281600b8501602087016154e4565b7f2054616d61676f67692028556e72657665616c2050726f707329222c20226465600b9390910192830152507f736372697074696f6e223a2022556e72657665616c2050726f7073222c000000602b8201526e2261747472696275746573223a205b60881b60488201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a605782015268202270726f7073227d60b81b607782015261174b60f21b60808201527f22696d616765223a2022697066733a2f2f516d5462423644443277387433367a60828201527f4c50764245646f576f363252464d794a69394558636a39395a6978507278432260a2820152607d60f81b60c282015260c301919050565b6a7b226e616d65223a20222360a81b81528651600090614e8481600b850160208c016154e4565b6e040a8c2dac2cedeced2408acece405608b1b600b918401918201528751614eb381601a840160208c016154e4565b602f60f81b601a92909101918201528651614ed581601b840160208b016154e4565b602960f81b9101601b8101919091527f222c20226465736372697074696f6e223a2022556e62726f6b656e2054616d61601c8201526d19dbd9da481959d9dccb8b8b888b60921b603c8201526e2261747472696275746573223a205b60881b604a820152614835614d19614b74614f8c614f7e614827614f78614f6b614f65614f6060598b0161457f565b6145ba565b8e6144c9565b602f60f81b815260010190565b8b6144c9565b61174b60f21b815260020190565b7f22696d616765223a2022697066733a2f2f516d57317463635971426d534c514681527f54664e38725777384a4858787837685a53344d6969775757444e35747647382f602082015260400190565b7f7b202274726169745f74797065223a20227265616374696f6e222c202276616c8152653ab2911d101160d11b60208201526000614a5a60268301846144e5565b693d913730b6b2911d101160b11b8152845160009061504281600a850160208a016154e4565b602360f81b600a91840191820152855161506381600b840160208a016154e4565b6a040a8c2dac2cedeced240560ab1b600b9290910191820152845161508f8160168401602089016154e4565b602f60f81b6016929091019182015283516150b18160178401602088016154e4565b602960f81b6017929091019182015261088b60f21b6018820152601a019695505050505050565b60006150e3826145ba565b84516150f38183602089016154e4565b602f60f81b910190815283516151108160018401602088016154e4565b61227d60f01b60019290910191820152600301949350505050565b7f7b202274726169745f74797065223a2022626f6479222c202276616c7565223a815261101160f11b60208201526000614a5a60228301846144e5565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516151a081601d8501602087016154e4565b91909101601d0192915050565b7f3c7376672077696474683d2239363022206865696768743d223936302220766581527f7273696f6e3d22312e31222076696577426f783d22302030203332203332222060208201527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660408201527f672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f7260608201526d3397989c9c9c97bc3634b735911f60911b60808201527f3c726563742077696474683d223130302522206865696768743d223130302522608e82015271103334b6361e9111b0b0b21c9c9c9110179f60711b60ae820152600082516152af8160c08501602087016154e4565b651e17b9bb339f60d11b60c093909101928301525060c601919050565b7f7b202274726169745f74797065223a202268656164222c202276616c7565223a815261101160f11b60208201526000614a5a60228301846144e5565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612fe19083018461449d565b6020808252825182820181905260009190848201906040850190845b81811015611d4d57835183529284019291840191600101615358565b60208152600061291a602083018461449d565b60a08152600061539a60a083018861449d565b90508560208301528460408301528360608301528260808301529695505050505050565b60208082526010908201526f139bdd081d985b1a59081c195d081a5960821b604082015260600190565b6020808252600a9082015269139bdd081c995d99585b60b21b604082015260600190565b6020808252600890820152674d617820746f203160c01b604082015260600190565b86815260208101869052604081018590528315156060820152821515608082015260c081016004831061547157634e487b7160e01b600052602160045260246000fd5b8260a0830152979650505050505050565b6000821982111561549557615495615574565b500190565b6000826154a9576154a961558a565b500490565b60008160001904831182151516156154c8576154c8615574565b500290565b6000828210156154df576154df615574565b500390565b60005b838110156154ff5781810151838201526020016154e7565b838111156120d95750506000910152565b600181811c9082168061552457607f821691505b60208210811415611a7c57634e487b7160e01b600052602260045260246000fd5b600060001982141561555957615559615574565b5060010190565b60008261556f5761556f61558a565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b03198116811461254157600080fdfe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220f1bbe7fca7f3263c3e811e6ceea38359c62c7b09c7e4845d05a74dcb604827eb64736f6c63430008070033608060405234801561001057600080fd5b5061152e806100206000396000f3fe608060405234801561001057600080fd5b506004361061030b5760003560e01c80638aa001fc1161019d578063c7b6fd6a116100e9578063de5101af116100a2578063f615ed541161007c578063f615ed541461068a578063f9fd52501461069d578063fa93f883146106a5578063ff2258cb146106b857600080fd5b8063de5101af1461065c578063e95564301461066f578063ea1c16901461067757600080fd5b8063c7b6fd6a1461060b578063c7edf88c1461061e578063c9d3462214610626578063cfbb9f3714610639578063d2b5074314610641578063d6582d0d1461064957600080fd5b80639e524caa11610156578063ad203bd411610130578063ad203bd4146105cc578063b05eb08d146105df578063b3bb8cd4146105f2578063b8d16dbc146105f857600080fd5b80639e524caa1461059c578063a324ad24146105af578063a3f144ae146105c257600080fd5b80638aa001fc146104f85780638bbf51b71461050b5780638d4a2d391461051357806390059aed146105265780639220d4261461055457806392d663131461058957600080fd5b80634355644d1161025c5780635e05bd6d116102155780637217523c116101ef5780637217523c146104b557806374f0314f146104c85780637be34109146104d257806389a3a00d146104e557600080fd5b80635e05bd6d1461047c57806362fb96971461048f57806365c72840146104a257600080fd5b80634355644d146104145780634371c46514610427578063442b8c791461043a578063444fda821461044d5780634b321502146104605780634df861261461047357600080fd5b80631f4f77b2116102c95780632af123b8116102a35780632af123b8146103c85780633293d007146103db5780633e239e1a146103ee5780633f9e0eb71461040157600080fd5b80631f4f77b21461039a57806322f8a2b8146103ad57806329441674146103c057600080fd5b80625015531461031057806302e98e0d1461033657806310848ddf14610349578063126702a01461035c57806314b2d6dc146103645780631e0582e914610387575b600080fd5b61032361031e366004611292565b6106cb565b6040519081526020015b60405180910390f35b610323610344366004611292565b6106de565b610323610357366004611279565b6106ea565b610323600281565b6103776103723660046112b4565b6106fb565b604051901515815260200161032d565b6103236103953660046112b4565b610710565b6103236103a83660046112b4565b61071d565b6103236103bb366004611279565b61072a565b610323600781565b6103236103d6366004611292565b610735565b6103776103e93660046112e0565b610741565b6103236103fc366004611279565b61075c565b61032361040f366004611292565b610767565b610323610422366004611292565b610773565b610377610435366004611279565b61077f565b610323610448366004611292565b61078a565b61032361045b366004611292565b610796565b61032361046e366004611292565b6107a2565b610323610e1081565b61032361048a3660046112e0565b6107ae565b61032361049d366004611292565b6107c8565b6103236104b0366004611279565b6107d4565b6103236104c3366004611292565b6107df565b6103236201518081565b6103236104e0366004611292565b6107eb565b6103236104f3366004611292565b6107f7565b610323610506366004611279565b610803565b610323600381565b610323610521366004611292565b61080e565b610539610534366004611279565b61081a565b6040805193845260208401929092529082015260600161032d565b61055c610835565b604080519687526020870195909552938501929092526060840152608083015260a082015260c00161032d565b610323610597366004611279565b61085a565b6103236105aa366004611292565b610865565b6103236105bd366004611279565b610871565b61032362253d8c81565b6103236105da366004611292565b61087c565b6103776105ed366004611279565b610888565b42610323565b610377610606366004611279565b610893565b610323610619366004611292565b61089e565b610323600681565b610323610634366004611292565b6108aa565b610323600481565b610323600581565b610377610657366004611279565b6108b6565b61053961066a366004611279565b6108c1565b610323603c81565b61055c610685366004611279565b6108dc565b610323610698366004611292565b610902565b610323600181565b6103236106b3366004611279565b61090e565b6103236106c6366004611292565b610919565b60006106d78383610925565b9392505050565b60006106d7838361094c565b60006106f582610971565b92915050565b6000610708848484610999565b949350505050565b60006107088484846109ef565b6000610708848484610b2c565b60006106f582610b47565b60006106d78383610b7b565b6000610751878787878787610b97565b979650505050505050565b60006106f582610bd7565b60006106d78383610bf5565b60006106d78383610c7b565b60006106f582610d4d565b60006106d78383610d62565b60006106d78383610d96565b60006106d78383610e17565b6000610751878787878787610e3e565b9695505050505050565b60006106d78383610e8f565b60006106f582610ea8565b60006106d78383610eba565b60006106d78383610ec9565b60006106d78383610f40565b60006106f582610f4d565b60006106d78383610f5a565b600080600061082884610f66565b9250925092509193909250565b60008060008060008061084742611002565b949b939a50919850965094509092509050565b60006106f582611043565b60006106d7838361105e565b60006106f58261106b565b60006106d7838361107d565b60006106f582611151565b60006106f58261118d565b60006106d783836111ad565b60006106d783836111bc565b60006106f5826111d9565b60008060006108cf846111ee565b9196909550909350915050565b6000806000806000806108ee87611002565b949c939b5091995097509550909350915050565b60006106d783836111ff565b60006106f58261120b565b60006106d78383611227565b6000610933610e1083611443565b61093d90846114a1565b9050828111156106f557600080fd5b60008183111561095b57600080fd5b603c61096784846114a1565b6106d791906113aa565b6000808061098a61098562015180866113aa565b610f66565b50915091506107088282610bf5565b60006107b284101580156109ad5750600083115b80156109ba5750600c8311155b156106d75760006109cb8585610bf5565b90506000831180156109dd5750808311155b156109e757600191505b509392505050565b60006107b2841015610a0057600080fd5b838383600062253d8c60046064600c610a1a600e88611462565b610a24919061137c565b610a3088611324611323565b610a3a9190611323565b610a44919061137c565b610a4f9060036113be565b610a59919061137c565b600c80610a67600e88611462565b610a71919061137c565b610a7c90600c6113be565b610a87600288611462565b610a919190611462565b610a9d9061016f6113be565b610aa7919061137c565b6004600c610ab6600e89611462565b610ac0919061137c565b610acc896112c0611323565b610ad69190611323565b610ae2906105b56113be565b610aec919061137c565b610af8617d4b87611462565b610b029190611323565b610b0c9190611323565b610b169190611462565b610b209190611462565b98975050505050505050565b600062015180610b3d8585856109ef565b6107089190611443565b600080610b5762015180846113aa565b90506007610b66826003611364565b610b7091906114b8565b6106d7906001611364565b600081831115610b8a57600080fd5b610e1061096784846114a1565b6000610ba4878787610999565b156107be57601884108015610bb95750603c83105b8015610bc55750603c82105b156107be575060019695505050505050565b600080610be762015180846114b8565b90506106d7610e10826113aa565b60008160011480610c065750816003145b80610c115750816005145b80610c1c5750816007145b80610c275750816008145b80610c32575081600a145b80610c3d575081600c145b15610c4a5750601f6106f5565b81600214610c5a5750601e6106f5565b610c6383611151565b610c6e57601c610c71565b601d5b60ff169392505050565b6000808080610c9061098562015180886113aa565b91945092509050610ca18583611364565b9150600c610cb06001846114a1565b610cba91906113aa565b610cc49084611364565b9250600c610cd36001846114a1565b610cdd91906114b8565b610ce8906001611364565b91506000610cf68484610bf5565b905080821115610d04578091505b610d1162015180886114b8565b62015180610d208686866109ef565b610d2a9190611443565b610d349190611364565b945086851015610d4357600080fd5b5050505092915050565b60006006610d5a83610b47565b101592915050565b6000808080610d7761098562015180886113aa565b91945092509050610d888584611364565b92506000610cf68484610bf5565b6000808080610dab61098562015180886113aa565b91945092509050610dbc85846114a1565b92506000610dca8484610bf5565b905080821115610dd8578091505b610de562015180886114b8565b62015180610df48686866109ef565b610dfe9190611443565b610e089190611364565b945086851115610d4357600080fd5b6000610e25610e1083611443565b610e2f9084611364565b9050828110156106f557600080fd5b600081610e4c603c85611443565b610e58610e1087611443565b62015180610e678b8b8b6109ef565b610e719190611443565b610e7b9190611364565b610e859190611364565b6107519190611364565b600081831115610e9e57600080fd5b6106d783836114a1565b600061070861098562015180846113aa565b6000610e256201518083611443565b600081831115610ed857600080fd5b600080610eeb61098562015180876113aa565b509092509050600080610f0461098562015180886113aa565b50909250905082610f1685600c611443565b82610f2285600c611443565b610f2c9190611364565b610f3691906114a1565b61075191906114a1565b6000610e25603c83611443565b60006106f5603c836114b8565b6000610e2f8284611364565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281610fc357610fc36114e2565b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b6000808080808061101862015180885b04610f66565b91999098919750610e10620151809092068281049750603c9290068281049650919091069350915050565b600061105561098562015180846113aa565b50909392505050565b6000610933603c83611443565b60006109e761098562015180846113aa565b600080808061109261098562015180886113aa565b919450925090506000856110a76001856114a1565b6110b286600c611443565b6110bc9190611364565b6110c691906114a1565b90506110d3600c826113aa565b93506110e0600c826114b8565b6110eb906001611364565b925060006110f98585610bf5565b905080831115611107578092505b61111462015180896114b8565b620151806111238787876109ef565b61112d9190611443565b6111379190611364565b95508786111561114657600080fd5b505050505092915050565b600061115e6004836114b8565b15801561117457506111716064836114b8565b15155b806106f55750611186610190836114b8565b1592915050565b6000806111a061098562015180856113aa565b505090506106d781611151565b60006109336201518083611443565b6000818311156111cb57600080fd5b6201518061096784846114a1565b600060056111e683610b47565b111592915050565b600080806108cf6201518085611012565b600061093d82846114a1565b60008061121a610e10846114b8565b90506106d7603c826113aa565b60008183111561123657600080fd5b600061124861098562015180866113aa565b505090506000611260620151808561098591906113aa565b50509050818161127091906114a1565b95945050505050565b60006020828403121561128b57600080fd5b5035919050565b600080604083850312156112a557600080fd5b50508035926020909101359150565b6000806000606084860312156112c957600080fd5b505081359360208301359350604090920135919050565b60008060008060008060c087890312156112f957600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b600080821280156001600160ff1b0384900385131615611345576113456114cc565b600160ff1b839003841281161561135e5761135e6114cc565b50500190565b60008219821115611377576113776114cc565b500190565b60008261138b5761138b6114e2565b600160ff1b8214600019841416156113a5576113a56114cc565b500590565b6000826113b9576113b96114e2565b500490565b60006001600160ff1b03818413828413808216868404861116156113e4576113e46114cc565b600160ff1b6000871282811687830589121615611403576114036114cc565b6000871292508782058712848416161561141f5761141f6114cc565b87850587128184161615611435576114356114cc565b505050929093029392505050565b600081600019048311821515161561145d5761145d6114cc565b500290565b60008083128015600160ff1b850184121615611480576114806114cc565b6001600160ff1b038401831381161561149b5761149b6114cc565b50500390565b6000828210156114b3576114b36114cc565b500390565b6000826114c7576114c76114e2565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fdfea26469706673582212202464ec77d55c0b8b938a36e973509d6bb0bb2d18b4f4c56e73bccd066d6eca6264736f6c6343000807003389504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000b9494441545847ed96c10e80200c4321faff5fec4139cce0dc68410c979178215bf7a81b21a794b6eb5bb672008403e14038100e8403e140384038705c31fbe08b05e6b20f1228640052390c0025e4380473110014207e4d53a30530a3b8f0b95a1ec08ce2b5c6278051189d67ea300e588965afac7a3cbd3d89e90228e2226815d2a22dbb2db0bb77d1140888770a298c00dc8b8c01d010f5e4590008fa31b97f01c0f193001640f70471ffbc9ad4cce901608b76c52d073801df502d81d35c52b50000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000060494441545847ed96410a00200804f3ff8f2e844e511a68e461bab74ea348d23e1ff95cbf0180010c9436d0e78e88429a39a770bd142dbceeb86d2600650d68ff32e7e098e50d5a068499e101444db80fb80178fa6500000318c00006308081013eee10210f9b3be30000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000089494441545847ed96b10ac0200c4423edff7f7187ea60493378977490c2096e313edf29d8ccece873db68029001199001199001199001c2c0d56bcee28f05ae653e24b0c9020eae4500b0016166d9230bc000c59a7f030cc3e3047ea00b99aa4711c4882b112cafc95780795a6f85817ca0b2003192b9b1d78e227a19a900102f8f2f11800c6c37700360131781b4054f830000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000080494441545847ed94410ac0200c04f5ff8f6ec921250475d7da22c87ad48d1927602d9b57dddcbf30005782ecd5e49c95c1fb51c02ecd196f14f75b3903e8ed3f6f1a01a0623f6773cd69af00f80b91ea21203382b70d284308c0b5cd6a8ef925032c401c4736f609c06fdf053b0201c8800cc8800cc8800cc8800cc8c0b9066edd51182171bab4cb0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000007e494441545847ed92510ac0300843dbfb1f7a459820d22e993f52c8be0a33f1edad73343fb379ff60009e1792998ddf43e550a995f84c3c237174ee0b2097a0a5bbf7109e017095b6001973889c39da438595e52788ad410460a13fff3e2f81d92b002a978fce3006e8b2caa00064400664400664400664400664a0ddc00276971321672fab0a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000091494441545847ed96b10e80200c444be4ffbfd8411848c060efda05872371f2da3e5ed050ccec6acfb1550420033220033220033220038481bb656af2c6026bd90b096cb401a46a1800aad1872158fb7b00b803e26cb83d9081a30068f8fc3e925da47906224d23d934c07b8867c0cbd2003dc80e8dc084003c88dd507ae783027d0523d71b6716fc85b30099e1548d001e930027810fe7f6160000000049454e44ae426082466f6f642077696c6c2062652061626c6520746f2070726576656e7420796f7572207065742066726f6d2073746172766174696f6e2e89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005e494441545847ed95390e00200cc3e8ff1fcd3180104294b64317334362792052928f24f717003080010c60c06aa0f6af5b7bf373672d8016769b8a5781a97c847b004e2873e91e100598e56e88284078cd01c000063080010c6020dd4003cbd40721aa0beb880000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000072494441545847ed94310e00210804f5ff8ff68ec2c4e2803d43a2c55859c0b219597b3b7cfae1f90d031080804260bc5155eabe129df666c2a980f08f841a91818ae1d39fabe519a81c1e9ac0c0b504ecdd2af7e0f712ae8b63f72cae5e1a6d70d8bf2b2cc45f2bc10004200001084000020fec3f1221ce89b1720000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000068494441545847ed94c10a00101404f9ff8f2607a5478c835cc64dedee5b4372fabcf2e7f9c902844019ae89e89b1c7b4e812d68d4c4fdea095d796e0bc4d3ad0ac4cc6de953813e90e8088d49438309fa188e3cb4c0b3efc20212908004242001094840021290400533b70d21044e4ab70000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000072494441545847ed94510a00210844ebfe876e290844dacd8996085e7fd1a8e353cae9f0c987eba7a881628cce62146dc8404d688bfabb85a8685bdcac9baa51922ada7b0d742aa3fdf544bfc6b544a02fd8dbe8fcfb1603b6e3c8ce48fa68c2dfbe0b0c40000210800004200001084000020fc5ac172190ff741b0000000049454e44ae426082546f79732063616e206b65657020796f7572207065742066726f6d206265696e6720626f7265642e89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000067494441545847ed954b0a00200805f3fe87eeb368994f2ab0605ae77318c3ac241f4bee5f00c00006be3050fbaed80595b5916019e22c33590b8032201506fe1237c303b8d17cf22db39e0618f4372c6c8f2030def32bea119e7710090060000318c00006d20d343af6102106b4da3d0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000063494441545847ed954b0a00200844f3fe87eeb3898848cdc0cd6b6d33d3131a29c94792fd0b012000010840c04ba0f6af5bbb6399990da0899daae266e0321fe2de001603cb4c88c04a6598bd3ce45b80709b7b571036dc05080001084000021080400354df0721739252ba0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005b494441545847edd5310e0020080441f9ffa3550a3b20014968d69620e714226bf8c8f0fc450004104000818ac0bedfb7d717d5cc5f3f1be00db006453577e56403b4efaedf00fa6a3de57bca8d5d1404400001041040008171810356ee0721ed9f05790000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a6494441545847ed96c10a80201883957aff27ee501e0493e9e6df218405dedcfcfe39c29c523a9ef5db970de0049c801370024ec009ec90c0f5409ec10703d5aaef016a0400258d0220190d12a25a06400d84ab997acc007ae10a8cac1d01208332ac5ac6a2eff7c30114802a8c24d06a96000a7d3f450400f9bc6ac34ad86e8e024c7bfa05a026540f68fb21c34601d001f4be51145b01d04281e2d2ffd44a02d42cb2c10037c7f12981ef4fbe3c0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000008f494441545847ed93d10e80200845f5ff3fba461b8de80a526daeedf6a628f778b4de167f7d717efb05c0662c09b01d23817e4d78c8cc8084d9357e8c004a7b228052234732bd1701a8e2cc4ef5fdc2be5eaf34ad2acf40908d3347c3d0ddeadcccbd8f20a21e476d04f0263483d1fa054026fdef96a97d52bf657cfdd0ca5004a0011aa0011aa0011aa0011aa0811d3de21d21bb35e40a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005b494441545847ed94db0900200cc474ffa17d2c604a058b10bfbdf408b4bd15bf5e3cbf5940031af8c2c058b7225b14b3044640e0901d195460f36f4a60960a2040031a7861203023ff85b6204f0e262da0010d6840031a283730013af6102192d097b20000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005f494441545847edd5bb0a00200846617dff87ae961a44f042e0721a237fe51b5265f8e8707f61000410400081aac03a5f77549379f3364014665745263cf3a63d80b7bb4a0d6d4055c013b977adac56d1cf15ce0008208000020820302eb00182580621fa639d260000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000061494441545847ed94410e00100c04f5ff8f460f8eac20a926e3cc760cad95e065c1f50b0018c0400a03b5cf8a5350795605cb808d41b6ccf81ae0c5ed87a069d6ca403880d3bf80c8fb07e4fbdd76809f575db051e36e0b0018c000063080010c343af61021f9935c500000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000067494441545847ed93410a00200cc3f4ff8f56100411ba513d8810cfb5ed32ade5f1a98ff3cb1705da46292b6de95db3d945dddbc3337db80265a64c5dfdf08908b886aefebac03a40162e873d7d03eeef9539590137c8d6530002108000042000010840000210e80b6d0b213ce71b1e0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000009e494441545847ed96410ac0200c0495f6ff2feea17a08b4c1646314bcacd05b930c936db19652aef61c3b9500344003344003344003341030f0b477eee48d05d6a20b496fd0cf0a805bef01ac0e17696e1f0b60d77008e10164b55b7119e621020083e404f45b3b05d07bca1a7684d0ec81be0201b1d68120a1bd1500dd7c346c1b80566835d63b87eb8b18d079404dd15a7e998d0224ffc4b88c00c70dbcedba1d81b2a5703a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af4000000017352474200aece1ce900000066494441545847edd5310e00100c85613d8efb1fc67108092961914a0dbfc540f25e3f0309ce4b9cf30305104000010410f84720c7982525e9fb8b5f7297d104eac11a58cb589638658c107dc13abc0fb2cb98a67cc9af4be8014d996f9e8c02082080000208145bcb2821effa51fe0000000049454e44ae426082536869656c6420746f2070726f7465637420796f7572207065742066726f6d206265696e67206869742e89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000049494441545847edd6410a00200804c0fcffa3ab17a40421c17857973988319a2b9af70f010810f84260ee5b711b34edad0c4e871c8e59da2b0001021581a72f8300040810204080c0023af610215e442abd0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000098494441545847ed964b0ac0200c0523f5fe27eea26621049b98f82952784237d53c27038a8988aef21d1b090030000330000330000330e018b8cb7c5e7cad7433220f921508b7d60370030276a60decd8bcf2995996819d9b77217e033063a4ad5133a2062c00fecf433baa9f03c80d34c02500eeaa76573bec055a736dc6ebd47af7802c90619a766f5ebd3246000277cef812001c37f00086f72381b52e906c0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000060494441545847edd6cb0a0020084451fdff8feeb16813e4580411dcd669c31124b7c7c71fbf6f044000812f044adb15a741656da6b16c122c33594b804860f049c6c408963dd4087ae138eaee9c23558bc02eebf5ef030110400001041040a0028cd31421444923dc0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000070494441545847ed92410ac0200c04f5ff8f6e9b4341aa761772082de34590641d27f656bc7af1fded3300c7652a609ffb28d0a999843b0676c1713eae15e0ddbb9db4029001c61f7acd5000919f8190bd0a4006fcde80f1c05c891a412edde806000318c000063080010c600003e5064e048315215641d2fc0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000074494441545847ed94310ec0200cc4e0ff8f2e4202d481e452a062317372674cd59c2e9f7cb93f298067027874c70b9b95771e6beff3ce4a9005e1959be03b0035b4ef47cadff3e365d57bd6c168b8f53dbb1d11801d08992f07dab5562dc87c39f0f77f02000c60000318c000063080010c60a000b8610b216fdcaceb0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a4494441545847ed964b0ac0200c05957aff1377515d0444f2796ac1169e20144c759c1831a794aeda8fb54c001aa0011aa0011aa0011a000cdc35a62cbe58c27f9107493f49fb9636426963db00e304b3000dd685f00c788b2319e90d991016c0eee25a9a5488cf0248ee10d5688c5a494815ecc084e5fb2b006d375296d6d86b06ac7ab600c20b480e0e9a0289ef2f22eff0853b5f05404f3c1c376b009e180d3c0ef000b15d1d81d94175870000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006a494441545847ed944b0a00200844ebfe87eeb310dae88404153c5741cc383cc55a2e57bddcbf10000210f882401bb7221b546a95b134d83864a14714e04473cbe77a7901a6c04a515210422f083c4b605d9ef9ceee81cddfd5678dd5e26dff130002108000042000810e4ece1021878663410000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a0494441545847ed96c10a8020104495faff2fee907b30ac5667b6840e8d10c4e2eaf3b98a39a5b494efb396052003322003322003322003a481adf45b83af162a877990500375e0602e02f006b098b5ab9151bc6b2f0ad00231ff063ab41001e84d58edb340a7dd8a00046bf0e83ecdc03f016011012daf8fa157606dac9ddf3b96f0f24245e81988dc03530dd4d5a2555540efb2baed1863e069f5537902d801343f25816dd4601b0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000075494441545847ed92410ec0200804f5ff8f6ee381a4c12a0b1ebc8ce765990cf676f9f5cbfb5b04f038c0286f71796e57e84bac3c8248cdadca5625a7179bf6650046768029062ceb81cb00eaf2ef1ff88328016497ef206400af4e515f9a89ee79fae9c279003080010c60000318c0000630808117a9bd1321772d676e0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000068494441545847ed94610b00100c44f9ff3f9a28b5165792d6eaf9a6e1eede965a82570dd62fe90c3443cc9b57b523e81b0243c09eb77b55935d4e63c0271ca914015f7f6e41a8819df84ab406efd44a7577be7133035fbe0c0c40000210800004200001084000021df3d61521c08b49860000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000064494441545847ed94490e00200803f1ff8f763978841a354193e16a6ceb80144bae92ec6f04800004be2050fbaed80d2aef2a6129b0b0c8428da703dc78fd04e46a79046e9a872108100de168c32835a8ea23843aa7e2ca5c9e13000210800004200081063eee1021a0220e8e0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000092494441545847ed96410ac0200c0495f6ff2feea1061a0852bb9b40f1b282d0431227630af6d6da31f6b6d5052003322003322003322003a4816bc49dc9570b95c33e48ac586541680680ea644107731140b5f39967698201f0e42c4ccc2b0358277eb015612162ece71c2003b34a78a70f241c3e2f5c0160fe86df00e295d8f7db7cd0875b81ac01a6fb548c006460bb811b903311813716c23a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000065494441545847edd4dd0a00100c8661bbff8ba61d90ffad24a9d7216bfb3c8984c74b1ecf0fdf04889dd42ab8b7aeb4f30868d3beee64afb98b1560362837a8cfbc75c393238025a06416afd6ec1ee5768627c0d5af82000820800002082080000208209000f7ce15214de4787a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000092494441545847ed96d10ac02008458dedffbf780fab072142f3ea06637083bd44dae9e8a2262247ff3e1b8d0034400334400334400334001ab8faba33f96a816290070994c8810b63770023788cecc957966d1e0f20244f96632c377322004f60e6d87f01a832355ded03adbfdb4bc85fe0d56f4e6e6d0095ae0a60255fe708f0aa01b429c3a65bef0fb4070af70e1642801b8ad723816807111a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006c494441545847edd4d10a4011108461deffa14951d2b2e342a8ff5c9d8bc98e8fc470f98b97e7876f0aa42aa51696f3ca8265b196ebff67a7b795f70a5803572576f3ee1d980d6bc4a382b5a1a5daf3026587cab92bf7c1cc7802c79f090a2080000208208000020820804006486e132187d8c7c60000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000074494441545847ed94410ec0200cc3e0ff8f66e3c01192954905c99c9bd432526b497e35797f01000318b8c6407befc557582be3945a45938326b30a4016189774d9b102f863f9e09b761d6d40d2efeaef7965a0cfec7c85cc3a005108b9dc3560988e8fb806e21b4412000c60000318c040ba81073af6102143c1dc740000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006d494441545847ed93410ac0200c04f5ff8f5602e6225476410896e979b39d0cb1b7e2af17ffbf3d0130962517569a534ab32838947ce4e419a530ca22276db4e572f6f3d41c807db3d3fd66ef7500f7d1fc03c0dddaca2b376015ba61003080010c60000318c0000630506e6002f73b0f211a4494500000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a2494441545847ed964b0ac030084413dafb9fb88bc642200dea980f94c204bad2eae4f92139a57494efb3932980044880044880044880040204aee2734ebe58e0bfe84102030484b9313c013b92577d66acdf098850d17cb612f04458b6ad02a4ae43b734fc9ffe18e981362912d0dba7086837954072acbda0d9a7c7108ed0ea0e402568e36b48b5fc2d99c8c4b83dd027a8782325f07c5e71d12a0e505e73a1801b9c8b2581c49959130000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000061494441545847ed95410a00200804ebff8f2e3a142115ae045ea6abad4e73b05a924f4d9e5f00c00006308001d540db56b7cdbe6ad78daf028c4663d02df7aa1d215400cf00cf9d05a302d8574cede13ee1e0af6f1c000c60000318c00006d20d745ccf0721d52fc6040000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af4000000017352474200aece1ce900000072494441545847ed943112c0200804cf49feffe214190a6752c1450a2dd65a605d9021e9d2c63300c000063060187824dd8bbbaa8cad165199c0004b73380051a363208dcf0082bc537cca49f31c6d205eb0750666f10e4499a36ac1b78f7f07d10277018cdfb67605000c60000318c000065e01921281db558cba0000000049454e44ae426082
Deployed Bytecode
0x6080604052600436106102885760003560e01c806370a082311161015a578063b88d4fde116100c1578063e985e9c51161007a578063e985e9c514610841578063ebd799cc1461088a578063ebf6e91d146108aa578063f2fde38b146108ca578063f59dfdfb146108ea578063fe55932a1461090a57600080fd5b8063b88d4fde1461077b578063c23c863b1461079b578063c87b56dd146107cb578063ca9c4b33146107eb578063d3a2da38146107f3578063df33fa311461082e57600080fd5b806391b7f5ed1161011357806391b7f5ed146106b657806395d89b41146106d65780639b993a1a146106eb578063a22cb4651461071b578063a22d58231461073b578063b6d225511461075b57600080fd5b806370a08231146105ba578063715018a6146105da5780637908213d146105ef57806379502c55146106205780638462151c1461066b5780638da5cb5b1461069857600080fd5b806335b34ca2116101fe5780635d186c9f116101b75780635d186c9f1461051d57806361fd3f62146105325780636352211e1461053a57806366d38ba91461055a5780636840690b1461057a5780636898f82b1461059a57600080fd5b806335b34ca2146104435780633cd434aa1461047357806341b3ba3d1461048857806342842e0e146104a8578063439bbfd2146104c85780635a353cd3146104e857600080fd5b806309a3849a1161025057806309a3849a1461035e5780630ea61c471461037e57806318160ddd146103c65780631c19c215146103ed5780631d80009a1461040d57806323b872dd1461042357600080fd5b806301ffc9a71461028d57806306fdde03146102c2578063081812fc146102e457806308a337331461031c578063095ea7b31461033e575b600080fd5b34801561029957600080fd5b506102ad6102a8366004614385565b61092a565b60405190151581526020015b60405180910390f35b3480156102ce57600080fd5b506102d761097c565b6040516102b99190615374565b3480156102f057600080fd5b506103046102ff36600461436c565b610a0e565b6040516001600160a01b0390911681526020016102b9565b34801561032857600080fd5b5061033c610337366004614328565b610a52565b005b34801561034a57600080fd5b5061033c610359366004614289565b610a6b565b34801561036a57600080fd5b5061033c61037936600461434a565b610b0b565b34801561038a57600080fd5b5061039e61039936600461436c565b610b20565b60408051948552921515602085015290151591830191909152151560608201526080016102b9565b3480156103d257600080fd5b5060025460015403600019015b6040519081526020016102b9565b3480156103f957600080fd5b5061033c61040836600461436c565b610f23565b34801561041957600080fd5b506103df60975481565b34801561042f57600080fd5b5061033c61043e366004614195565b61105b565b34801561044f57600080fd5b506102ad61045e366004614147565b60b26020526000908152604090205460ff1681565b34801561047f57600080fd5b5061033c6111ec565b34801561049457600080fd5b5061033c6104a336600461436c565b611205565b3480156104b457600080fd5b5061033c6104c3366004614195565b611212565b3480156104d457600080fd5b5061033c6104e3366004614328565b611232565b3480156104f457600080fd5b5061050861050336600461436c565b611247565b604080519283526020830191909152016102b9565b34801561052957600080fd5b5061033c61156b565b61033c611582565b34801561054657600080fd5b5061030461055536600461436c565b6116c8565b34801561056657600080fd5b5061033c61057536600461436c565b6116d3565b34801561058657600080fd5b506102ad61059536600461436c565b611715565b3480156105a657600080fd5b5061033c6105b536600461436c565b611a82565b3480156105c657600080fd5b506103df6105d5366004614147565b611b30565b3480156105e657600080fd5b5061033c611b7f565b3480156105fb57600080fd5b5061060f61060a36600461436c565b611b93565b6040516102b9959493929190615387565b34801561062c57600080fd5b50609854609954609a5460ac546106599392919060ff808216916101008104821691620100009091041686565b6040516102b99695949392919061542e565b34801561067757600080fd5b5061068b610686366004614147565b611c49565b6040516102b9919061533c565b3480156106a457600080fd5b506000546001600160a01b0316610304565b3480156106c257600080fd5b5061033c6106d136600461436c565b611d59565b3480156106e257600080fd5b506102d7611d66565b3480156106f757600080fd5b506102ad61070636600461436c565b60af6020526000908152604090205460ff1681565b34801561072757600080fd5b5061033c61073636600461424d565b611d75565b34801561074757600080fd5b5061033c610756366004614328565b611e0b565b34801561076757600080fd5b5061050861077636600461436c565b611e20565b34801561078757600080fd5b5061033c6107963660046141d1565b612095565b3480156107a757600080fd5b506102ad6107b6366004614147565b60b16020526000908152604090205460ff1681565b3480156107d757600080fd5b506102d76107e636600461436c565b6120df565b61033c6120ea565b3480156107ff57600080fd5b506102ad61080e3660046143bf565b805160208183018101805160b08252928201919093012091525460ff1681565b61033c61083c3660046142b3565b612222565b34801561084d57600080fd5b506102ad61085c366004614162565b6001600160a01b03918216600090815260086020908152604080832093909416825291909152205460ff1690565b34801561089657600080fd5b5061033c6108a5366004614328565b612410565b3480156108b657600080fd5b5061033c6108c536600461436c565b612425565b3480156108d657600080fd5b5061033c6108e5366004614147565b6124cb565b3480156108f657600080fd5b5061033c61090536600461436c565b612544565b34801561091657600080fd5b5061033c610925366004614421565b6125ea565b60006301ffc9a760e01b6001600160e01b03198316148061095b57506380ac58cd60e01b6001600160e01b03198316145b806109765750635b5e139f60e01b6001600160e01b03198316145b92915050565b60606003805461098b90615510565b80601f01602080910402602001604051908101604052809291908181526020018280546109b790615510565b8015610a045780601f106109d957610100808354040283529160200191610a04565b820191906000526020600020905b8154815290600101906020018083116109e757829003601f168201915b5050505050905090565b6000610a19826127e4565b610a36576040516333d1c03960e21b815260040160405180910390fd5b506000908152600760205260409020546001600160a01b031690565b610a5a612819565b610a6760a4826003613f53565b5050565b6000610a76826116c8565b9050336001600160a01b03821614610aaf57610a92813361085c565b610aaf576040516367d9dca160e11b815260040160405180910390fd5b60008281526007602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b610b13612819565b610a6760a7826005613f91565b60ac54600090819081908190610100900460ff16610b595760405162461bcd60e51b8152600401610b50906153e8565b60405180910390fd5b609954859081118015610b6e5750609a548111155b610b8a5760405162461bcd60e51b8152600401610b50906153be565b600086815260ae6020526040808220815160a081019092528054429392919082908290610bb690615510565b80601f0160208091040260200160405190810160405280929190818152602001828054610be290615510565b8015610c2f5780601f10610c0457610100808354040283529160200191610c2f565b820191906000526020600020905b815481529060010190602001808311610c1257829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b8152600401610cb4929190918252602082015260400190565b60206040518083038186803b158015610ccc57600080fd5b505afa158015610ce0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d049190614408565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b891610d48918890600401918252602082015260400190565b60206040518083038186803b158015610d6057600080fd5b505afa158015610d74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d989190614408565b905060008360600151600014610dc957603c846060015186610dba91906154cd565b610dc4919061549a565b610dcc565b60005b9050600060a18101548211610df35760a460005b0154610dec90836154ae565b9050610e27565b60a254821015610e065760a46001610de0565b60a354821015610e195760a46002610de0565b610e248260006154ae565b90505b6000610e356106868e6116c8565b90506000806000805b8451811015610ef1576000858281518110610e5b57610e5b6155b6565b602002602001015190506098600101548111610ede57600081815260ad602052604081205490600a610e8d8184615560565b600a8110610e9d57610e9d6155b6565b0154905080610eb35760009b5060019650610edb565b8060011415610ec95760009a5060019550610edb565b8060021415610edb5760009850600194505b50505b5080610ee981615545565b915050610e3e565b50600085610eff898b615482565b610f099190615482565b9f50929d50909b5099505050505050505050509193509193565b8033610f2e826116c8565b6001600160a01b031614610f805760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610b50565b60ac54610100900460ff16610fa75760405162461bcd60e51b8152600401610b50906153e8565b609954829081118015610fbc5750609a548111155b610fd85760405162461bcd60e51b8152600401610b50906153be565b600083815260af602052604090205460ff16156110275760405162461bcd60e51b815260206004820152600d60248201526c4e6f7420617661696c61626c6560981b6044820152606401610b50565b61103083612873565b600093845260ad602090815260408086209290925560af9052909220805460ff191660011790555050565b6000611066826128cc565b9050836001600160a01b0316816001600160a01b0316146110995760405162a1148160e81b815260040160405180910390fd5b60008281526007602052604090208054338082146001600160a01b038816909114176110e6576110c9863361085c565b6110e657604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b03851661110d57604051633a954ecd60e21b815260040160405180910390fd5b801561111857600082555b6001600160a01b038681166000908152600660205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260056020526040902055600160e11b83166111a357600184016000818152600560205260409020546111a15760015481146111a15760008181526005602052604090208490555b505b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b6111f4612819565b60ac805461ff001916610100179055565b61120d612819565b609755565b61122d83838360405180602001604052806000815250612095565b505050565b61123a612819565b610a67609e826003613f53565b60ac546000908190610100900460ff166112735760405162461bcd60e51b8152600401610b50906153e8565b6099548390811180156112885750609a548111155b6112a45760405162461bcd60e51b8152600401610b50906153be565b600084815260ae6020526040808220815160a0810190925280544293929190829082906112d090615510565b80601f01602080910402602001604051908101604052809291908181526020018280546112fc90615510565b80156113495780601f1061131e57610100808354040283529160200191611349565b820191906000526020600020905b81548152906001019060200180831161132c57829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b81526004016113ce929190918252602082015260400190565b60206040518083038186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e9190614408565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b891611462918890600401918252602082015260400190565b60206040518083038186803b15801561147a57600080fd5b505afa15801561148e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b29190614408565b905060006114c26106868a6116c8565b905060005b815181101561155c5760008282815181106114e4576114e46155b6565b60200260200101519050609860010154811161154957600081815260ad602052604081205490600a6115168184615560565b600a8110611526576115266155b6565b01549050806115385760009650611546565b806001141561154657600095505b50505b508061155481615545565b9150506114c7565b50919650945050505050915091565b611573612819565b60ac805460ff19166001179055565b600160ac5462010000900460ff1660038111156115a1576115a16155a0565b146115ee5760405162461bcd60e51b815260206004820152601860248201527f4e6f7420696e20737461676520746f206275792070726f7000000000000000006044820152606401610b50565b60995460015460001901106116355760405162461bcd60e51b815260206004820152600d60248201526c139bc81c1c9bdc1cc81b19599d609a1b6044820152606401610b50565b33600090815260b1602052604090205460ff16156116655760405162461bcd60e51b8152600401610b509061540c565b60006116746001546000190190565b61167f906001615482565b9050600061168c82612873565b600083815260ad6020526040902081905590506116aa33600161293c565b505033600090815260b160205260409020805460ff19166001179055565b6000610976826128cc565b6116db612819565b8060038111156116ed576116ed6155a0565b60ac805462ff000019166201000083600381111561170d5761170d6155a0565b021790555050565b6000816098600101548111801561172e5750609a548111155b61174a5760405162461bcd60e51b8152600401610b50906153be565b600083815260ae6020526040808220815160a0810190925280548290829061177190615510565b80601f016020809104026020016040519081016040528092919081815260200182805461179d90615510565b80156117ea5780601f106117bf576101008083540402835291602001916117ea565b820191906000526020600020905b8154815290600101906020018083116117cd57829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000429050600060ad600087815260200190815260200160002054905060006301e133808261184c9190615560565b60965460808601519192506001600160a01b0316906365c7284090611872908490615482565b6040518263ffffffff1660e01b815260040161189091815260200190565b60206040518083038186803b1580156118a857600080fd5b505afa1580156118bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e09190614408565b6096546040516301971ca160e61b8152600481018690526001600160a01b03909116906365c728409060240160206040518083038186803b15801561192457600080fd5b505afa158015611938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195c9190614408565b148015611a75575060965460808501516001600160a01b039091169063a324ad2490611989908490615482565b6040518263ffffffff1660e01b81526004016119a791815260200190565b60206040518083038186803b1580156119bf57600080fd5b505afa1580156119d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f79190614408565b6096546040516328c92b4960e21b8152600481018690526001600160a01b039091169063a324ad249060240160206040518083038186803b158015611a3b57600080fd5b505afa158015611a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a739190614408565b145b9550505050505b50919050565b60ac54610100900460ff16611aa95760405162461bcd60e51b8152600401610b50906153e8565b609954819081118015611abe5750609a548111155b611ada5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600290910155815184815233918101919091527fd0017656a8c92d10b2fa3a77fa3c1e8e4c28817e89311616b8eed8e68f68a95091015b60405180910390a15050565b60006001600160a01b038216611b59576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526006602052604090205467ffffffffffffffff1690565b611b87612819565b611b916000612956565b565b60ae60205260009081526040902080548190611bae90615510565b80601f0160208091040260200160405190810160405280929190818152602001828054611bda90615510565b8015611c275780601f10611bfc57610100808354040283529160200191611c27565b820191906000526020600020905b815481529060010190602001808311611c0a57829003601f168201915b5050505050908060010154908060020154908060030154908060040154905085565b60606000806000611c5985611b30565b905060008167ffffffffffffffff811115611c7657611c766155cc565b604051908082528060200260200182016040528015611c9f578160200160208202803683370190505b509050611ccc60408051608081018252600080825260208201819052918101829052606081019190915290565b60015b838614611d4d57611cdf816129a6565b9150816040015115611cf057611d45565b81516001600160a01b031615611d0557815194505b876001600160a01b0316856001600160a01b03161415611d455780838780600101985081518110611d3857611d386155b6565b6020026020010181815250505b600101611ccf565b50909695505050505050565b611d61612819565b609855565b60606004805461098b90615510565b6001600160a01b038216331415611d9f5760405163b06307db60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b611e13612819565b610a67609b826003613f53565b6000808260986001015481118015611e3a5750609a548111155b611e565760405162461bcd60e51b8152600401610b50906153be565b600084815260ae6020526040808220815160a08101909252805482908290611e7d90615510565b80601f0160208091040260200160405190810160405280929190818152602001828054611ea990615510565b8015611ef65780601f10611ecb57610100808354040283529160200191611ef6565b820191906000526020600020905b815481529060010190602001808311611ed957829003601f168201915b505050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250509050600060ad600087815260200190815260200160002054905060006301e1338082611f539190615560565b60965460808501519192506000916001600160a01b039091169063a324ad2490611f7e908590615482565b6040518263ffffffff1660e01b8152600401611f9c91815260200190565b60206040518083038186803b158015611fb457600080fd5b505afa158015611fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fec9190614408565b60965460808601519192506000916001600160a01b03909116906365c7284090612017908690615482565b6040518263ffffffff1660e01b815260040161203591815260200190565b60206040518083038186803b15801561204d57600080fd5b505afa158015612061573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120859190614408565b9197509095505050505050915091565b6120a084848461105b565b6001600160a01b0383163b156120d9576120bc84848484612a25565b6120d9576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b606061097682612b1d565b600360ac5462010000900460ff166003811115612109576121096155a0565b146121565760405162461bcd60e51b815260206004820152601960248201527f4e6f7420696e20737461676520746f206d696e7420544d4747000000000000006044820152606401610b50565b609a54600154600019011061219b5760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610b50565b33600090815260b2602052604090205460ff16156121cb5760405162461bcd60e51b8152600401610b509061540c565b60985434906121db9060016154ae565b111561221a5760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610b50565b611b91612bec565b600260ac5462010000900460ff166003811115612241576122416155a0565b1461228e5760405162461bcd60e51b815260206004820181905260248201527f4e6f7420696e20737461676520746f206d696e74206d65726b6c6520544d47476044820152606401610b50565b609a5460015460001901106122d35760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610b50565b33600090815260b2602052604090205460ff16156123035760405162461bcd60e51b8152600401610b509061540c565b60985434906123139060016154ae565b11156123525760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610b50565b6040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506123cc838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506097549150849050612d7e565b6124085760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610b50565b61122d612bec565b612418612819565b610a6760a1826003613f53565b60ac54610100900460ff1661244c5760405162461bcd60e51b8152600401610b50906153e8565b6099548190811180156124615750609a548111155b61247d5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600390910155815184815233918101919091527fbae6551c0ddf25aa6805100ecbdc4535f2933a14d7ebafe9fab66af752e232ec9101611b24565b6124d3612819565b6001600160a01b0381166125385760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b50565b61254181612956565b50565b60ac54610100900460ff1661256b5760405162461bcd60e51b8152600401610b50906153e8565b6099548190811180156125805750609a548111155b61259c5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600190910155815184815233918101919091527fd73f65a9b0fee6c2e3e08fd03cb4800137b36882554a7211fe8ce842b3d4f4fe9101611b24565b82336125f5826116c8565b6001600160a01b0316146126475760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610b50565b60ac54610100900460ff1661266e5760405162461bcd60e51b8152600401610b50906153e8565b6099548490811180156126835750609a548111155b61269f5760405162461bcd60e51b8152600401610b50906153be565b60b084846040516126b19291906145f3565b9081526040519081900360200190205460ff16156126fe5760405162461bcd60e51b815260206004820152600a60248201526913985b5948195e1a5cdd60b21b6044820152606401610b50565b600061273f85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d9492505050565b90506001811180156127515750601281105b61278e5760405162461bcd60e51b815260206004820152600e60248201526d4e6f742076616c6964206e616d6560901b6044820152606401610b50565b600086815260ae602052604090206127a7908686613fbe565b50600160b086866040516127bc9291906145f3565b908152604051908190036020019020805491151560ff19909216919091179055505050505050565b6000816001111580156127f8575060015482105b8015610976575050600090815260056020526040902054600160e01b161590565b6000546001600160a01b03163314611b915760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b50565b6000806128816001436154cd565b6040805191406020830152810184905233606090811b6bffffffffffffffffffffffff19169082015260740160408051601f1981840301815291905280516020909101209392505050565b600081806001116129235760015481101561292357600081815260056020526040902054600160e01b8116612921575b8061291a5750600019016000818152600560205260409020546128fc565b9392505050565b505b604051636f96cda160e11b815260040160405180910390fd5b610a67828260405180602001604052806000815250612ed1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60408051608081018252600080825260208201819052918101829052606081019190915260008281526005602052604090205461097690604080516080810182526001600160a01b038316815260a083901c67ffffffffffffffff166020820152600160e01b831615159181019190915260e89190911c606082015290565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a0290612a5a903390899088908890600401615309565b602060405180830381600087803b158015612a7457600080fd5b505af1925050508015612aa4575060408051601f3d908101601f19168201909252612aa1918101906143a2565b60015b612aff573d808015612ad2576040519150601f19603f3d011682016040523d82523d6000602084013e612ad7565b606091505b508051612af7576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490505b949350505050565b60608160018110158015612b375750600154600019018111155b612b725760405162461bcd60e51b815260206004820152600c60248201526b139bdd081d985b1a59081a5960a21b6044820152606401610b50565b609954600090841115612ba55760ac54610100900460ff16612b9c57612b9784612f3e565b612bc1565b612b9784612feb565b60ac5460ff16612bb857612b978461313a565b612bc18461315a565b905080604051602001612bd49190615168565b60405160208183030381529060405292505050919050565b6000612bfb6001546000190190565b612c06906001615482565b905060b45460051415612ca357600060b45560965460b354604051631c85d48f60e21b81526004810191909152600160248201526001600160a01b0390911690637217523c9060440160206040518083038186803b158015612c6757600080fd5b505afa158015612c7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9f9190614408565b60b3555b6040805160c081018252600060a082018181528252426020808401829052838501919091526060830182905260b354608084015284825260ae81529290208151805192938493612cf69284920190614031565b5060208201516001820155604082015160028201556060820151600382015560809091015160049091015560b48054906000612d3183615545565b91905055506000612d4183612873565b600084815260ad602052604090208190559050612d5f33600161293c565b505033600090815260b260205260409020805460ff1916600117905550565b600082612d8b85846132ff565b14949350505050565b600080825b8051821015612eca576007818381518110612db657612db66155b6565b01602001516001600160f81b031990811690911c16612de157612dda600183615482565b9150612eb8565b8051600360f91b90600590839085908110612dfe57612dfe6155b6565b01602001516001600160f81b031990811690911c161415612e2457612dda600283615482565b8051600760f91b90600490839085908110612e4157612e416155b6565b01602001516001600160f81b031990811690911c161415612e6757612dda600383615482565b8051600f60f91b90600390839085908110612e8457612e846155b6565b01602001516001600160f81b031990811690911c161415612eaa57612dda600483615482565b612eb5600183615482565b91505b82612ec281615545565b935050612d99565b5050919050565b612edb838361334c565b6001600160a01b0383163b1561122d576001548281035b612f056000868380600101945086612a25565b612f22576040516368d2bf6b60e11b815260040160405180910390fd5b818110612ef2578160015414612f3757600080fd5b5050505050565b6060600080612f4c84611e20565b600086815260ad6020526040812054929450909250612fe1612f6d87613443565b612f7686613443565b612f7f86613443565b612f8888613443565b612f9188613443565b612fb8601a612fa160038b615560565b60038110612fb157612fb16155b6565b0154613443565b604051602001612fcd96959493929190614e5d565b604051602081830303815290604052613541565b9695505050505050565b6060600080600080612ffc86610b20565b935093509350935060008061301088611247565b91509150600061301f89611715565b9050600086801561302d5750855b80156130365750845b8061303e5750815b61304957600061304c565b60015b90506000613059896136a7565b905060006040518060c001604052808d815260200160ad60008f81526020019081526020016000205481526020018781526020018681526020018b8152602001841515815250905060006130c160ad60008f8152602001908152602001600020548486613707565b905060006130ce83613ae9565b6130d784613c7b565b6130e085613cc1565b6130e986613d6e565b6130fa6130f587613da7565b613541565b60405160200161310e959493929190614689565b604051602081830303815290604052905061312881613541565b9e9d5050505050505050505050505050565b6060600061291a61314a84613443565b604051602001612fcd9190614d2b565b600081815260ad6020526040812054606091600a6131788184615560565b600a8110613188576131886155b6565b015490506000601782600381106131a1576131a16155b6565b0180546131ad90615510565b80601f01602080910402602001604051908101604052809291908181526020018280546131d990615510565b80156132265780601f106131fb57610100808354040283529160200191613226565b820191906000526020600020905b81548152906001019060200180831161320957829003601f168201915b50505050509050600060148360038110613242576132426155b6565b01805461324e90615510565b80601f016020809104026020016040519081016040528092919081815260200182805461327a90615510565b80156132c75780601f1061329c576101008083540402835291602001916132c7565b820191906000526020600020905b8154815290600101906020018083116132aa57829003601f168201915b5050505050905060006132f46132dc88613443565b83858586604051602001612fcd959493929190614b88565b979650505050505050565b600081815b84518110156133445761333082868381518110613323576133236155b6565b6020026020010151613dd0565b91508061333c81615545565b915050613304565b509392505050565b6001548161336d5760405163b562e8dd60e01b815260040160405180910390fd5b6001600160a01b03831660008181526006602090815260408083208054680100000000000000018802019055848352600590915281206001851460e11b4260a01b178317905582840190839083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600183015b81811461341c57808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a46001016133e4565b508161343a57604051622e076360e81b815260040160405180910390fd5b60015550505050565b6060816134675750506040805180820190915260018152600360fc1b602082015290565b8160005b8115613491578061347b81615545565b915061348a9050600a8361549a565b915061346b565b60008167ffffffffffffffff8111156134ac576134ac6155cc565b6040519080825280601f01601f1916602001820160405280156134d6576020820181803683370190505b5090505b8415612b15576134eb6001836154cd565b91506134f8600a86615560565b613503906030615482565b60f81b818381518110613518576135186155b6565b60200101906001600160f81b031916908160001a90535061353a600a8661549a565b94506134da565b606081516000141561356157505060408051602081019091526000815290565b60006040518060600160405280604081526020016155f960409139905060006003845160026135909190615482565b61359a919061549a565b6135a59060046154ae565b905060006135b4826020615482565b67ffffffffffffffff8111156135cc576135cc6155cc565b6040519080825280601f01601f1916602001820160405280156135f6576020820181803683370190505b509050818152600183018586518101602084015b81831015613662576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f811685015182535060010161360a565b60038951066001811461367c576002811461368d57613699565b613d3d60f01b600119830152613699565b603d60f81b6000198301525b509398975050505050505050565b60a75460009082116136c057602a60035b015492915050565b60a8548210156136d357602a60006136b8565b60a9548210156136e657602a60016136b8565b60aa548210156136f957602a60026136b8565b602a60046136b8565b919050565b60606000608b600b61371a60048861549a565b6137249190615560565b600b8110613734576137346155b6565b01805461374090615510565b80601f016020809104026020016040519081016040528092919081815260200182805461376c90615510565b80156137b95780601f1061378e576101008083540402835291602001916137b9565b820191906000526020600020905b81548152906001019060200180831161379c57829003601f168201915b5050505050905060006080600b6003886137d3919061549a565b6137dd9190615560565b600b81106137ed576137ed6155b6565b0180546137f990615510565b80601f016020809104026020016040519081016040528092919081815260200182805461382590615510565b80156138725780601f1061384757610100808354040283529160200191613872565b820191906000526020600020905b81548152906001019060200180831161385557829003601f168201915b505050505090506000606e600d60028961388c919061549a565b6138969190615560565b600d81106138a6576138a66155b6565b0180546138b290615510565b80601f01602080910402602001604051908101604052809291908181526020018280546138de90615510565b801561392b5780601f106139005761010080835404028352916020019161392b565b820191906000526020600020905b81548152906001019060200180831161390e57829003601f168201915b505050505090506000607b8760058110613947576139476155b6565b01805461395390615510565b80601f016020809104026020016040519081016040528092919081815260200182805461397f90615510565b80156139cc5780601f106139a1576101008083540402835291602001916139cc565b820191906000526020600020905b8154815290600101906020018083116139af57829003601f168201915b5050505050905060006139de85613dfc565b6139e785613dfc565b6139f084613dfc565b6139f986613dfc565b604051602001613a0c9493929190614632565b60405160208183030381529060405290508615613add5780613aba606d6000018054613a3790615510565b80601f0160208091040260200160405190810160405280929190818152602001828054613a6390615510565b8015613ab05780601f10613a8557610100808354040283529160200191613ab0565b820191906000526020600020905b815481529060010190602001808311613a9357829003601f168201915b5050505050613dfc565b604051602001613acb929190614603565b60405160208183030381529060405290505b98975050505050505050565b6060600080613afb8460000151611e20565b91509150600060ae6000866000015181526020019081526020016000206040518060a0016040529081600082018054613b3390615510565b80601f0160208091040260200160405190810160405280929190818152602001828054613b5f90615510565b8015613bac5780601f10613b8157610100808354040283529160200191613bac565b820191906000526020600020905b815481529060010190602001808311613b8f57829003601f168201915b50505050508152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006001613bf08360000151612d94565b11613c0a5760405180602001604052806000815250613c2c565b8151604051613c1c9190602001614842565b6040516020818303038152906040525b905080613c3c8760000151613443565b613c4586613443565b613c4e86613443565b604051602001613c61949392919061501c565b604051602081830303815290604052945050505050919050565b60606000613c8c8360400151613443565b613c998460600151613443565b604051602001613caa92919061493d565b60408051601f198184030181529190529392505050565b606060008260a00151613cee57604051806040016040528060028152602001616e6f60f01b815250613d0b565b6040518060400160405280600381526020016279657360e81b8152505b9050600081613d1d8560800151613443565b613d2686613e17565b613d2f87613e4b565b613d3888613ea3565b613d4189613efb565b604051602001613d5696959493929190614a6d565b60408051601f19818403018152919052949350505050565b6060600080613d808460000151611e20565b91509150613d8d82613443565b613d9682613443565b604051602001612bd49291906150d8565b606081604051602001613dba91906151ad565b6040516020818303038152906040529050919050565b6000818310613dec57600082815260208490526040902061291a565b5060009182526020526040902090565b6060613e0782613541565b604051602001613dba9190614869565b606060006052613e2a84608001516136a7565b60058110613e3a57613e3a6155b6565b01604051602001613caa9190614fdb565b606060006045601d600d60028660200151613e66919061549a565b613e709190615560565b600d8110613e8057613e806155b6565b0154600d8110613e9257613e926155b6565b01604051602001613caa9190614a1e565b606060006057602f600b60038660200151613ebe919061549a565b613ec89190615560565b600b8110613ed857613ed86155b6565b0154600b8110613eea57613eea6155b6565b01604051602001613caa91906152cc565b606060006062603a600b60048660200151613f16919061549a565b613f209190615560565b600b8110613f3057613f306155b6565b0154600b8110613f4257613f426155b6565b01604051602001613caa919061512b565b8260038101928215613f81579160200282015b82811115613f81578235825591602001919060010190613f66565b50613f8d9291506140a5565b5090565b8260058101928215613f815791602002820182811115613f81578235825591602001919060010190613f66565b828054613fca90615510565b90600052602060002090601f016020900481019282613fec5760008555613f81565b82601f106140055782800160ff19823516178555613f81565b82800160010185558215613f815791820182811115613f81578235825591602001919060010190613f66565b82805461403d90615510565b90600052602060002090601f01602090048101928261405f5760008555613f81565b82601f1061407857805160ff1916838001178555613f81565b82800160010185558215613f81579182015b82811115613f8157825182559160200191906001019061408a565b5b80821115613f8d57600081556001016140a6565b600067ffffffffffffffff808411156140d5576140d56155cc565b604051601f8501601f19908116603f011681019082821181831017156140fd576140fd6155cc565b8160405280935085815286868601111561411657600080fd5b858560208301376000602087830101525050509392505050565b80356001600160a01b038116811461370257600080fd5b60006020828403121561415957600080fd5b61291a82614130565b6000806040838503121561417557600080fd5b61417e83614130565b915061418c60208401614130565b90509250929050565b6000806000606084860312156141aa57600080fd5b6141b384614130565b92506141c160208501614130565b9150604084013590509250925092565b600080600080608085870312156141e757600080fd5b6141f085614130565b93506141fe60208601614130565b925060408501359150606085013567ffffffffffffffff81111561422157600080fd5b8501601f8101871361423257600080fd5b614241878235602084016140ba565b91505092959194509250565b6000806040838503121561426057600080fd5b61426983614130565b91506020830135801515811461427e57600080fd5b809150509250929050565b6000806040838503121561429c57600080fd5b6142a583614130565b946020939093013593505050565b600080602083850312156142c657600080fd5b823567ffffffffffffffff808211156142de57600080fd5b818501915085601f8301126142f257600080fd5b81358181111561430157600080fd5b8660208260051b850101111561431657600080fd5b60209290920196919550909350505050565b60006060828403121561433a57600080fd5b82606083011115611a7c57600080fd5b600060a0828403121561435c57600080fd5b8260a083011115611a7c57600080fd5b60006020828403121561437e57600080fd5b5035919050565b60006020828403121561439757600080fd5b813561291a816155e2565b6000602082840312156143b457600080fd5b815161291a816155e2565b6000602082840312156143d157600080fd5b813567ffffffffffffffff8111156143e857600080fd5b8201601f810184136143f957600080fd5b612b15848235602084016140ba565b60006020828403121561441a57600080fd5b5051919050565b60008060006040848603121561443657600080fd5b83359250602084013567ffffffffffffffff8082111561445557600080fd5b818601915086601f83011261446957600080fd5b81358181111561447857600080fd5b87602082850101111561448a57600080fd5b6020830194508093505050509250925092565b600081518084526144b58160208601602086016154e4565b601f01601f19169290920160200192915050565b600081516144db8185602086016154e4565b9290920192915050565b8054600090600181811c90808316806144ff57607f831692505b602080841082141561452157634e487b7160e01b600052602260045260246000fd5b818015614535576001811461454657614573565b60ff19861689528489019650614573565b60008881526020902060005b8681101561456b5781548b820152908501908301614552565b505084890196505b50505050505092915050565b7f7b202274726169745f74797065223a202274797065222c202276616c7565223a81526808089c195d1cc89f4b60ba1b602082015260290190565b7f7b202274726169745f74797065223a2022626972746864617465222c20227661815266363ab2911d101160c91b602082015260270190565b8183823760009101908152919050565b600083516146158184602088016154e4565b8351908301906146298183602088016154e4565b01949350505050565b60008551614644818460208a016154e4565b855190830190614658818360208a016154e4565b855191019061466b8183602089016154e4565b845191019061467e8183602088016154e4565b019695505050505050565b6000865161469b818460208b016154e4565b80830190507f226465736372697074696f6e223a202254616d61676f6769206973206120546181527f6d61676f74636869204461707020616e642066756c6c792067656e657261746560208201527f64206f6e2d636861696e2e2054686520636f6e747261637420696e746572616360408201527f74696f6e20616e642074696d652077696c6c206166666563742074686520737460608201527f6174757320616e64207265616374696f6e206f6620746865207065742e20496660808201527f20796f7520636f6c6c656374206f74686572206974656d732c2074686520706560a0820152721d081dda5b1b081cda1bddc81b1bdd9948488b606a1b60c08201526e2261747472696275746573223a205b60881b60d382015286516147c88160e2840160208b016154e4565b6148356148276148216147e96147e360e2868801018c6144c9565b8a6144c9565b7f5d2c22696d616765223a2022646174613a696d6167652f7376672b786d6c3b62815265185cd94d8d0b60d21b602082015260260190565b876144c9565b61227d60f01b815260020190565b9998505050505050505050565b600082516148548184602087016154e4565b6201017960ed1b920191825250600301919050565b7f3c696d61676520783d22302220793d2230222077696474683d2233322220686581527f696768743d2233322220696d6167652d72656e646572696e673d22706978656c60208201527f6174656422207072657365727665417370656374526174696f3d22784d69645960408201527f4d69642220786c696e6b3a687265663d22646174613a696d6167652f706e673b60608201526618985cd94d8d0b60ca1b6080820152600082516149238160878501602087016154e4565b6211179f60e91b6087939091019283015250608a01919050565b7f7b202274726169745f74797065223a202268756e676572222c2022646973706c81527f61795f74797065223a20226e756d626572222c202276616c7565223a2000000060208201526000835161499b81603d8501602088016154e4565b8083019050611f4b60f21b80603d8301527f7b202274726169745f74797065223a2022626f726564222c2022646973706c61603f8301527f795f74797065223a20226e756d626572222c202276616c7565223a2000000000605f8301528451614a0b81607b8501602089016154e4565b607b920191820152607d01949350505050565b7f7b202274726169745f74797065223a2022656172222c202276616c7565223a208152601160f91b60208201526000614a5a60218301846144e5565b62089f4b60ea1b81526003019392505050565b6000614a788261457f565b7f7b202274726169745f74797065223a20226d6173746572222c202276616c7565815263111d101160e11b60208201528851614abb816024840160208d016154e4565b62089f4b60ea1b602492909101918201527f7b202274726169745f74797065223a2022756e68617070696e657373222c202260278201527f646973706c61795f74797065223a20226e756d626572222c202276616c75652260478201526101d160f51b60678201528751614b36816069840160208c016154e4565b611f4b60f21b606992909101918201528651614b5981606b840160208b016154e4565b614b7a614b74614b6e606b848601018a6144c9565b886144c9565b866144c9565b9a9950505050505050505050565b6a7b226e616d65223a20222360a81b81528551600090614baf81600b850160208b016154e4565b6a040a8c2dac2cedeced240560ab1b600b918401918201528651614bda816016840160208b016154e4565b7314911610113232b9b1b934b83a34b7b7111d101160611b601692909101918201528551614c0f81602a840160208a016154e4565b61088b60f21b9101602a8101919091526e2261747472696275746573223a205b60881b602c8201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a603b8201526908089c1c9bdc1cc89f4b60b21b605b8201527f7b202274726169745f74797065223a20227573616765222c202276616c7565226065820152621d101160e91b6085820152613add614d19614b74614cca614cba608886016147e3565b63089f574b60e21b815260040190565b7f22696d616765223a2022697066733a2f2f516d56784344666d7767593270734181527f683777746938614c43796b6b6a3939736e79674751383970327a6b664174662f602082015260400190565b652e676966227d60d01b815260060190565b6a7b226e616d65223a20222360a81b81528151600090614d5281600b8501602087016154e4565b7f2054616d61676f67692028556e72657665616c2050726f707329222c20226465600b9390910192830152507f736372697074696f6e223a2022556e72657665616c2050726f7073222c000000602b8201526e2261747472696275746573223a205b60881b60488201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a605782015268202270726f7073227d60b81b607782015261174b60f21b60808201527f22696d616765223a2022697066733a2f2f516d5462423644443277387433367a60828201527f4c50764245646f576f363252464d794a69394558636a39395a6978507278432260a2820152607d60f81b60c282015260c301919050565b6a7b226e616d65223a20222360a81b81528651600090614e8481600b850160208c016154e4565b6e040a8c2dac2cedeced2408acece405608b1b600b918401918201528751614eb381601a840160208c016154e4565b602f60f81b601a92909101918201528651614ed581601b840160208b016154e4565b602960f81b9101601b8101919091527f222c20226465736372697074696f6e223a2022556e62726f6b656e2054616d61601c8201526d19dbd9da481959d9dccb8b8b888b60921b603c8201526e2261747472696275746573223a205b60881b604a820152614835614d19614b74614f8c614f7e614827614f78614f6b614f65614f6060598b0161457f565b6145ba565b8e6144c9565b602f60f81b815260010190565b8b6144c9565b61174b60f21b815260020190565b7f22696d616765223a2022697066733a2f2f516d57317463635971426d534c514681527f54664e38725777384a4858787837685a53344d6969775757444e35747647382f602082015260400190565b7f7b202274726169745f74797065223a20227265616374696f6e222c202276616c8152653ab2911d101160d11b60208201526000614a5a60268301846144e5565b693d913730b6b2911d101160b11b8152845160009061504281600a850160208a016154e4565b602360f81b600a91840191820152855161506381600b840160208a016154e4565b6a040a8c2dac2cedeced240560ab1b600b9290910191820152845161508f8160168401602089016154e4565b602f60f81b6016929091019182015283516150b18160178401602088016154e4565b602960f81b6017929091019182015261088b60f21b6018820152601a019695505050505050565b60006150e3826145ba565b84516150f38183602089016154e4565b602f60f81b910190815283516151108160018401602088016154e4565b61227d60f01b60019290910191820152600301949350505050565b7f7b202274726169745f74797065223a2022626f6479222c202276616c7565223a815261101160f11b60208201526000614a5a60228301846144e5565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516151a081601d8501602087016154e4565b91909101601d0192915050565b7f3c7376672077696474683d2239363022206865696768743d223936302220766581527f7273696f6e3d22312e31222076696577426f783d22302030203332203332222060208201527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660408201527f672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f7260608201526d3397989c9c9c97bc3634b735911f60911b60808201527f3c726563742077696474683d223130302522206865696768743d223130302522608e82015271103334b6361e9111b0b0b21c9c9c9110179f60711b60ae820152600082516152af8160c08501602087016154e4565b651e17b9bb339f60d11b60c093909101928301525060c601919050565b7f7b202274726169745f74797065223a202268656164222c202276616c7565223a815261101160f11b60208201526000614a5a60228301846144e5565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612fe19083018461449d565b6020808252825182820181905260009190848201906040850190845b81811015611d4d57835183529284019291840191600101615358565b60208152600061291a602083018461449d565b60a08152600061539a60a083018861449d565b90508560208301528460408301528360608301528260808301529695505050505050565b60208082526010908201526f139bdd081d985b1a59081c195d081a5960821b604082015260600190565b6020808252600a9082015269139bdd081c995d99585b60b21b604082015260600190565b6020808252600890820152674d617820746f203160c01b604082015260600190565b86815260208101869052604081018590528315156060820152821515608082015260c081016004831061547157634e487b7160e01b600052602160045260246000fd5b8260a0830152979650505050505050565b6000821982111561549557615495615574565b500190565b6000826154a9576154a961558a565b500490565b60008160001904831182151516156154c8576154c8615574565b500290565b6000828210156154df576154df615574565b500390565b60005b838110156154ff5781810151838201526020016154e7565b838111156120d95750506000910152565b600181811c9082168061552457607f821691505b60208210811415611a7c57634e487b7160e01b600052602260045260246000fd5b600060001982141561555957615559615574565b5060010190565b60008261556f5761556f61558a565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b03198116811461254157600080fdfe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220f1bbe7fca7f3263c3e811e6ceea38359c62c7b09c7e4845d05a74dcb604827eb64736f6c63430008070033
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.