ETH Price: $3,331.82 (-0.35%)

Token

Good Morning Cafe: Keekusaurs (KEEK)
 

Overview

Max Total Supply

3,333 KEEK

Holders

1,038

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
1 KEEK
0x75EC2e2976decAe6303b7C6AE6C453C3A98b4D72
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

Still the chillest café in all of the verses. Succulent vibes. Art. Cowffee. 💖 Meet the **Keekusaurs** — 3333 majestic creatures chugging down cowffees on the Ethereum blockchain. Adopt a precious and tender Keekusaur to join the world and future of the [Good Morning Café](https://www.gmcafe.io/) as we share moist succulence far and wide. These tender **Keekusaurs** were frozen in mysteriously supercharged ice for a millennia, deep in a cave on the GMCafé Estate. After being discovered, the Moos of **Kawa Valley** graciously gave them the clothes (and traits) off their floofy backs and taught them to way of the **Herd**.

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
KEEK

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 333 runs

Other Settings:
default evmVersion
File 1 of 12 : KEEK.sol
/*                 cHONKNMgmoo                                                                                  
				   NNM   "3NMNMggy                            gNMNNMg_     ggMp     moo         qMMp   cHONkggy 
				  -NNE       j2MMNNgggjj_                     NNNMNMMM_    MNNMp    NMM&        gMMP   gNMMNNNNy
				   MMg,jqqgMMMMMMNNMMNMMMNMggqyj              MNM  NNM:   jNN lML   "NNM  gNgy jNNM    MNNl MNN"
				   gNNNNMM9?:            '?9NNMMMgq_          NMNNNNM"    gNN lNM,   MNMgMNMNMggNM&    MNNNNNNy 
	_chONKMMNMMNNNNNMPl                        '9NNNMg_       MMMNNMMg    NMNMMMNg   9MMNMM&NMNMMNl    NMNP9MMM;
   gMMN99?""""qNNMR.                               ?MNNgy    -MMN  MNN)  jMMN33MMNy   NNNM&  NMMM&    (NNM  3NNM
   NNM      jgMNO                                     MMMMj  :MMN  dMNM  dNM&  JMM&   3MN&    3MN"    7NM&   3NM
   7NMg    gMNP                                        'MMNg  ?0l   ?9l  """"  '"""                              
	?NNgj gMN"                                           9NNp             ,                                     
	  9MMNNN"                                             3MNy          jNM&                                    
		gNN"                                               NMN         qMNNF                                    
   mooMMNN&                                                :NN&      gMMMN"                                     
jMMMMNMNNN                                           jggy   MOO      '23                                        
NNM    MM&               cgqg            qg&        gMMMNM  9MM                                                 
NMgy  _NME              MOONMM          gNNMNg      MKEEKM  7MN~                                                
 9NMggJMM\              NNNMMM          ""  '"       "?3"   :MN)                                                
   9MMNNM:               """"                               :MMC                                                
	  3NMC                                                   MNp                          https://www.gmcafe.io/
	   MOO                                                   N*/
/// @author raffy.eth
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import {Ownable} from "@openzeppelin/[email protected]/access/Ownable.sol";
import {IERC165} from "@openzeppelin/[email protected]/utils/introspection/IERC165.sol";
import {IERC721} from "@openzeppelin/[email protected]/token/ERC721/IERC721.sol";
import {IERC721Metadata} from "@openzeppelin/[email protected]/token/ERC721/extensions/IERC721Metadata.sol";
import {IERC721Receiver} from "@openzeppelin/[email protected]/token/ERC721/IERC721Receiver.sol";
import {IERC2981} from "@openzeppelin/[email protected]/interfaces/IERC2981.sol";
import {DefaultOperatorFilterer} from "[email protected]/src/DefaultOperatorFilterer.sol";

interface KEEKURI {
	function render(uint256 td, uint256 od) external view returns (string memory uri);
}

contract KEEK is Ownable, IERC165, IERC721, IERC721Metadata, IERC2981, DefaultOperatorFilterer {

	function supportsInterface(bytes4 x) external pure returns (bool) {
		return x == type(IERC165).interfaceId         // 0x01ffc9a7 
		    || x == type(IERC721).interfaceId         // 0x80ac58cd
		    || x == type(IERC721Metadata).interfaceId // 0x5b5e139f
		    || x == type(IERC2981).interfaceId        // 0x2a55205a
			|| x == 0x7f5828d0  // https://eips.ethereum.org/EIPS/eip-173  (Ownable)
		    || x == 0x49064906; // https://eips.ethereum.org/EIPS/eip-4906 (Metadata Update Extension)
	}

	event MetadataUpdate(uint256 token);

	// pref packing:
	// 0000000FFF 12 token
	// 000000F000  4 pref
	// 0000FF0000  8 mint
	// FFFF000000 16 index
	event SetPref(uint256 packed);
	event Locked(uint256 token);
	event Unlocked(uint256 token);
	event UnlockAttempt(uint256 token);
	event MerkleRootChanged();

	error InvalidInput();
	error InvalidReceiver();
	error InvalidLockState();
	error NotAllowed();

	// token allocation:
	// 001-300  moo direct     300
	// 301-333  moo custom      33
	// 334-337  FND (4)          4
	// 338-345  team(4) x2       8
	// 346-353  barista(4) x2    8
	// 354-386  treasury        33
	// 387      audit            1
	// 388-XXX  mintable      2946
	// Total[{300, 33, 4, 8, 8, 33, 1, 2946}] = 3333
	uint256 constant DROPPED_SUPPLY = 387;

	// mint data packing:
	uint256 constant MD_PREFABLE_BIT    =        0x0000000000000000000000000000000000000000000000000000000000000001; // 1
	uint256 constant MD_MINTABLE_SHIFT  = 1;  // 0x0000000000000000000000000000000000000000000000000000000000011110     4
	uint256 constant MD_INDEX_SHIFT		= 5;  // 0x0000000000000000000000000000000011111111111111111111111111100000     X
	uint256 constant MD_MINTABLE_MASK   = 0xF;

	// owner balance packing:
	//               OB_OWNED_SHIFT     =  0; // 0x0000000000000000000000000000000000000000000000000000000000000FFF    12
	uint256 constant OB_MINTED_SHIFT    = 12; // 0x0000000000000000000000000000000000000000000000000000000000FFF000    12
	uint256 constant OB_RESERVATION_BIT =        0x0000000000000000000000000000000000000000000000000000000001000000; // 1
	uint256 constant OB_PUBLIC_BIT      =        0x0000000000000000000000000000000000000000000000000000000002000000; // 1
	uint256 constant OB_ACQUIRE_SHIFT   = 26; // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE000000     X
	uint256 constant OB_OWNED_MASK      = 0xFFF;
	uint256 constant OB_MINTED_MASK     = 0xFFF;
	uint256 constant OB_ACQUIRE_1       = (1 << OB_ACQUIRE_SHIFT) | 1;
	uint256 constant OB_MINT_1          = (1 << OB_MINTED_SHIFT) | 1;

	// token data packing:
	// FoldList[Plus, 0, {160, 32, 32, 15, 1, 4, 12}] = {0, 160, 192, 224, 239, 240, 244, 256}
	//               TD_OWNER_SHIFT    =   0; // 0x000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF   160
	uint256 constant TD_BLOCK_SHIFT    = 160; // 0x0000000000000000FFFFFFFF0000000000000000000000000000000000000000    32
	uint256 constant TD_TRANSFER_SHIFT = 192; // 0x00000000FFFFFFFF000000000000000000000000000000000000000000000000    32
	uint256 constant TD_TAG_SHIFT      = 224; // 0x00007FFF00000000000000000000000000000000000000000000000000000000    15
	uint256 constant TD_LOCK_BIT       =         0x0000800000000000000000000000000000000000000000000000000000000000; // 1
	uint256 constant TD_PREF_SHIFT     = 240; // 0x000F000000000000000000000000000000000000000000000000000000000000     4
	uint256 constant TD_TOKEN_SHIFT    = 244; // 0xFFF0000000000000000000000000000000000000000000000000000000000000    12

	uint256 constant TD_TAG_MASK       = 0x7FFF; // 15
	uint256 constant TD_PREF_PICK      = 0x8;    // 1000 (influence bit)
	uint256 constant TD_PREF_MASK      = 0xF;    // 1111 (+3 choices)
	uint256 constant TD_TOKEN_MASK     = 0xFFF;  // 12
	uint256 constant TD_COPY_MASK      = (TD_TOKEN_MASK << TD_TOKEN_SHIFT) | (TD_PREF_MASK << TD_PREF_SHIFT);
	
	struct Unlock {
		bytes32 hash;  // hash of your password
		uint256 price; // recovery price you set
	}

	mapping (address => uint256) _ownerBalance;
	mapping (uint256 => uint256) _tokenData;
	mapping (uint256 => Unlock)  _tokenUnlock;
	mapping (uint256 => address) _tokenApproval;
	mapping (address => mapping(address => bool)) _operatorApprovals;

	address constant TEAM_MULTISIG = 0xa050F07d0a880B7C9389A782250d6848bA433854;
	function withdraw() external {
		uint256 b = address(this).balance;
		if (b == 0) revert InvalidInput();
		uint256 p = b / 20; // 5%
		payable(0xf29c7Db01873Db03D7dE5d0F238b1E08d0c7EDD8).transfer(p);      // eoa: raffy
		payable(0x6A1e88B4ef7098347F078ebC4D8fBFc064dEfb8A).transfer(p);      // eoa: loop 
		payable(0xDb513d3d4bd419A7c3AD24e363B3B6E8CCACB67E).transfer(p << 1); // eoa: jane 
		payable(0xb23Db186161bA869C06fAED618d0a0263bDB75C3).transfer(p << 2); // eoa: ben
		payable(TEAM_MULTISIG).transfer(b - (p << 3));
	}

	string public name = "Good Morning Cafe: Keekusaurs";
	string public symbol = "KEEK";

	bool _prefsLocked;
	bytes32 _merkleRoot;
	uint256 _mintPrice = 0.06 ether;
	uint256 _supply;
	uint256 _maxSupply = 3333;
	uint256 _lastToken = DROPPED_SUPPLY;
	uint256 _publicMax;

	address public _tokenURIContract;
	string public _tokenURIPrefix = "https://api.gmcafe.io/metadata/keek/";
	string public _tokenURISuffix = ".json";
	address _royaltyReceiver = TEAM_MULTISIG;
	uint256 _royaltyNumer = 50_000; // 5%
	uint256 constant ROYALTY_DENOM = 1_000_000;

	function totalSupply() public view returns (uint256) {
		return _supply;
	}
	
	// metadata
	function setTokenURIContract(address addr) onlyOwner public {
		_tokenURIContract = addr;
	}
	function setTokenURIPrefix(string calldata prefix) onlyOwner public {
		_tokenURIPrefix = prefix;
	}
	function setTokenURISuffix(string calldata suffix) onlyOwner public {
		_tokenURISuffix = suffix;
	}
	function tokenURI(uint256 token) public view returns (string memory uri) {
		uint256 td = _tokenData[token];
		if (td == 0) revert InvalidInput(); // ERC721
		if (_tokenURIContract != address(0)) {
			address owner = address(uint160(td));
			uri = KEEKURI(_tokenURIContract).render(td, _ownerBalance[owner]);
		}
		if (bytes(uri).length == 0) {
			bytes memory prefix = bytes(_tokenURIPrefix);
			bytes memory suffix = bytes(_tokenURISuffix);
			unchecked {
				uri = new string(prefix.length + 4 + suffix.length); // "3333"
			}
			uint256 ptr;
			assembly {
				ptr := uri
			}
			ptr = _appendBytes(ptr, prefix);
			uint256 len = token >= 100 ? token >= 1000 ? 4 : 3 : token >= 10 ? 2 : 1;
			ptr = _appendInt(ptr, token, len);
			ptr = _appendBytes(ptr, suffix);
			assembly {
				mstore(uri, sub(ptr, uri)) // truncate
			}	
		}
	}
	function _appendBytes(uint256 ptr, bytes memory data) private pure returns (uint256 dst) {
		uint256 src;
		assembly {
			src := data
			dst := add(ptr, mload(data)) // truncate
		}
		while (ptr < dst) {
			assembly {
				ptr := add(ptr, 32)
				src := add(src, 32)
				mstore(ptr, mload(src))
			}
		}
	}
	function _appendInt(uint256 ptr, uint256 value, uint256 len) private pure returns (uint256 dst) {
		uint256 bits = len << 3;
		uint256 buf;
		unchecked {
			for (uint256 i; i < bits; i += 8) {
				uint256 x = value % 10;
				buf |= (48 + x) << i;
				value /= 10;
			}
		}
		assembly {
			dst := add(ptr, len)
			mstore(dst, or(shl(bits, mload(ptr)), buf)) 
		}
	}

	// royalties
	function setRoyaltyInfo(address receiver, uint256 numer) onlyOwner external {
		if (numer > (receiver == address(0) ? 0 : ROYALTY_DENOM)) revert InvalidInput();
		_royaltyReceiver = receiver;
		_royaltyNumer = numer;
	}
	function getRoyaltyInfo() external view returns (address receiver, uint256 numer, uint256 denom) {
		receiver = _royaltyReceiver;
		numer = _royaltyNumer;
		denom = ROYALTY_DENOM;
	}
	function royaltyInfo(uint256, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount) {
		receiver = _royaltyReceiver;
		royaltyAmount = (salePrice * _royaltyNumer) / ROYALTY_DENOM;
	}

	// tagging
	function setTag(uint256 token, uint256 tag) external {
		if (tag > TD_TAG_MASK) revert InvalidInput(); // too large
		uint256 td = _tokenData[token];
		_requireApprovedSender(address(uint160(td)), token);
		uint256 tag0 = (td >> TD_TAG_SHIFT) & TD_TAG_MASK;
		if (tag0 == tag) revert InvalidInput(); // no change
		_tokenData[token] = td ^ ((tag ^ tag0) << TD_TAG_SHIFT);
	}

	// locking
	function isKeekLocked(uint256 token) external view returns (bool) {
		return _isLocked(_tokenData[token]);
	}
	function _isLocked(uint256 td) private pure returns (bool) {
		return (td & TD_LOCK_BIT) > 0;
	}
	function makePasswordHash(uint256 token, string memory password) pure public returns (bytes32) {
		return keccak256(abi.encodePacked(token, password));
	}
	function lockKeek(uint256 token, uint256 price, bytes32 hash) external {
		uint256 td = _tokenData[token];
		if (_isLocked(td)) revert InvalidLockState(); // already locked
		_requireApprovedSender(address(uint160(td)), token); 
		if (price > 0) { // password only applies when non-zero
			_tokenUnlock[token] = Unlock({hash: hash, price: price});
		}
		_tokenData[token] = td | TD_LOCK_BIT;
		emit Locked(token);
		emit MetadataUpdate(token);
	}
	function unlockKeek(uint256 token, string memory password, address transfer) payable public {
		uint256 td = _tokenData[token];
		if (!_isLocked(td)) revert InvalidLockState(); // not locked
		address owner = address(uint160(td));
		_requireApprovedSender(owner, token); 
		Unlock storage unlock = _tokenUnlock[token];
		uint256 price = unlock.price;
		if (price > 0) { // must satisfy one of the following:
			if (msg.value == 0) { // check password
				if (unlock.hash != makePasswordHash(token, password)) { // wrong password
					emit UnlockAttempt(token);
					return;
				}
			} else if (msg.value < price) { // check price
				revert InvalidLockState(); // not enough
			}
			delete _tokenUnlock[token]; // clear storage
		}
		_tokenData[token] = td ^ TD_LOCK_BIT; // clear lock
		emit Unlocked(token);
		emit MetadataUpdate(token);
		if (transfer != address(0)) {
			safeTransferFrom(owner, transfer, token, ''); // could be a contract
		}
	}
	function rescueKeek(uint256 token) onlyOwner public {
		// if the keek was locked and the owner gave this contract approval,
		// admin can break the lock and obtain the keek
		uint256 td = _tokenData[token];
		if (!_isLocked(td)) revert InvalidLockState(); // not locked
		address owner = address(uint160(td));
		if (!isApprovedForAll(owner, address(this)) && _tokenApproval[token] != address(this)) revert NotAllowed();
		delete _tokenUnlock[token]; // clear storage
		_tokenData[token] = td ^ TD_LOCK_BIT; // clear lock
		emit Unlocked(token);
		emit MetadataUpdate(token);
		if (owner != msg.sender) { 
			_approvedTransfer(owner, msg.sender, token); 
		}
	}

	// minting
	function reduceSupply(uint256 supply) onlyOwner external {
		if (supply >= _maxSupply) revert InvalidInput(); // must decrease
		if (supply < _lastToken) revert InvalidInput(); // too low
		_maxSupply = supply;
	}
	function setMintPrice(uint256 priceWei) onlyOwner external {
		_mintPrice = priceWei;
	}
	function setMerkleRoot(bytes32 hash) onlyOwner external {
		_merkleRoot = hash;
		emit MerkleRootChanged();
	}
	function setPublicMax(uint256 max) onlyOwner external {
		_publicMax = max;
	}
	function getMintInfo() external view returns (
		uint256 price, uint256 supply, uint256 dropped, 
		uint256 minted, uint256 publicMax, bool prefsLocked
	) {
		price = _mintPrice;
		supply = _maxSupply;
		minted = _lastToken - DROPPED_SUPPLY;
		dropped = _supply - minted;
		publicMax = _publicMax;
		prefsLocked = _prefsLocked;
	}
	function hasMinted(uint256 md, address minter) external view returns (bool) {
		uint256 index = md >> MD_INDEX_SHIFT;
		return (_ownerBalance[minter] & (index > 0 ? OB_RESERVATION_BIT : OB_PUBLIC_BIT)) > 0;
	}
	function mintKeeks(bytes32[] calldata proof, uint256 md, uint256[] calldata prefs) external payable {
		unchecked {
			require(msg.sender == tx.origin, "only eoa"); 
			uint256 index = md >> MD_INDEX_SHIFT;			
			bool prefable;
			uint256 ob = _ownerBalance[msg.sender];
			uint256 bit;
			if (index > 0) {
				bit = OB_RESERVATION_BIT;
				prefable = (md & MD_PREFABLE_BIT) > 0; // only reservations can have prefs 
			} else { 
				bit = OB_PUBLIC_BIT;
			}
			require((ob & bit) == 0, "already minted");
			ob |= bit; // mark minted
			uint256 mintable; // mint limit
			if (md == 0) { // proof = <ignored>, index = 0, prefable = false
				mintable = _publicMax;
			} else {
				mintable = (md >> MD_MINTABLE_SHIFT) & MD_MINTABLE_MASK; 
				bytes32 node = keccak256(abi.encodePacked(msg.sender, md));
				for (uint256 i; i < proof.length; i++) {
					bytes32 b = proof[i];
					node = b < node ? keccak256(abi.encodePacked(b, node)) : keccak256(abi.encodePacked(node, b));
				}
				require(node == _merkleRoot, "bad proof");
			}
			require(prefs.length <= mintable, "bad quantity");
			uint256 token = _lastToken;
			uint256 avail = min(_maxSupply - token, prefs.length); // prevent overmint
			require(avail > 0, "max supply");
			uint256 value = _mintPrice * avail;
			require(msg.value >= value, "bad value");
			_supply += avail; // update supply
			_lastToken = token + avail; // update mint index
			_ownerBalance[msg.sender] = ob + OB_MINT_1 * avail; // +owned/minted
			for (uint256 i; i < avail; i++) {
				++token;
				uint256 pref;
				if (prefable) {
					pref = prefs[i] & TD_PREF_MASK;
					if (pref >= TD_PREF_PICK) {
						emit SetPref((index << 24) | (i << 16) | (pref << 12) | token);
					}
				}
				_mint(token, msg.sender, pref);	
			}
			uint256 refund = msg.value - value;
			if (refund > 0) {
				payable(msg.sender).transfer(refund);
			}
		}
	}
	function airdropKeeks(uint256[] calldata recs) onlyOwner external {
		unchecked {
			for (uint256 i; i < recs.length; i++) {
				uint256 rec = recs[i];
				address owner = address(uint160(rec));
				if (owner == address(0)) revert InvalidInput();
				uint256 token = rec >> 160;
				if (token == 0 || token > DROPPED_SUPPLY) revert InvalidInput();
				if (_tokenData[token] > 0) revert NotAllowed();
				_mint(token, owner, 0);		
				_ownerBalance[owner] += OB_MINT_1; // +owned/minted
			}
		}
		_supply += recs.length;
	}
	function _mint(uint256 token, address owner, uint256 pref) private {
		_tokenData[token] = (token << TD_TOKEN_SHIFT)
			| (pref << TD_PREF_SHIFT)
			| (block.number << TD_BLOCK_SHIFT) 
			| uint160(owner);
		emit Transfer(address(0), owner, token);
	}

	// airdrop preferences
	function lockPrefs() onlyOwner external {
		if (_prefsLocked) revert InvalidInput(); // already locked
		_prefsLocked = true;
	}
	function setPref(uint256 token, uint256 pref) external {
		if (_prefsLocked) revert NotAllowed();
		if (token > DROPPED_SUPPLY) revert NotAllowed();
		if (pref < TD_PREF_PICK || pref > TD_PREF_MASK) revert InvalidInput();
		_requireApprovedSender(msg.sender, token);
		uint256 td = _tokenData[token];
		uint256 pref0 = (td >> TD_PREF_SHIFT) & TD_PREF_MASK;
		if (pref0 > 0) revert NotAllowed();		
		_tokenData[token] = td | (pref << TD_PREF_SHIFT);
		emit SetPref((pref << 12) | token);
	}

	// transfer
	function safeTransferFrom(address from, address to, uint256 token) external {
		safeTransferFrom(from, to, token, '');
	}
	function safeTransferFrom(address from, address to, uint256 token, bytes memory data) public {
		transferFrom(from, to, token);
		if (to.code.length > 0) {
			try IERC721Receiver(to).onERC721Received(msg.sender, from, token, data) returns (bytes4 ret) {
				require(ret == IERC721Receiver.onERC721Received.selector);
			} catch (bytes memory reason) {
				if (reason.length == 0) {
					revert InvalidReceiver();
				} else {
					assembly {
						revert(add(reason, 32), mload(reason))
					}
				}
			}
		}
	}
	function transferFrom(address from, address to, uint256 token) onlyAllowedOperator(from) public {
		if (to == address(0)) revert InvalidReceiver(); // ERC721
		_requireApprovedSender(from, token); // from is owner
		_approvedTransfer(from, to, token);
	}
	function _approvedTransfer(address from, address to, uint256 token) private {
		if (to == from) revert InvalidReceiver(); // block transfer to self
		uint256 td = _tokenData[token];
		if (address(uint160(td)) != from) revert NotAllowed(); // not owned by from
		require(!_isLocked(td), "Keek is Locked"); // use string because user-facing error
		delete _tokenApproval[token]; // clear token approval
		unchecked {
			uint256 transfers = uint32((td >> TD_TRANSFER_SHIFT) + 1);
			_tokenData[token] = td & TD_COPY_MASK  // keep token and pref
				| (block.number << TD_BLOCK_SHIFT) // current block
				| (transfers << TD_TRANSFER_SHIFT) // updated transfer count
				| uint160(to);                     // new owner
			_ownerBalance[from]--;                 // -owned 
			_ownerBalance[to] += OB_ACQUIRE_1;     // +owned/acquire
		}
		emit Transfer(from, to, token);
	}

	// getters
	function balanceOf(address owner) external view returns (uint256) {
		if (owner == address(0)) revert InvalidInput(); // ERC721
		return _ownerBalance[owner] & OB_OWNED_MASK;
	}
	function ownerOf(uint256 token) public view returns (address) {
		return address(uint160(_tokenData[token]));
	}
	function getOwnerInfo(address owner) external view returns (
		uint16 owned, uint16 minted, uint256 acquired, 
		bool mintedReservation, bool mintedPublic
	) {
		uint256 ob = _ownerBalance[owner];
		owned = uint16(ob & OB_OWNED_MASK);
		minted = uint16((ob >> OB_MINTED_SHIFT) & OB_MINTED_MASK);
		acquired = ob >> OB_ACQUIRE_SHIFT;
		mintedReservation = (ob & OB_RESERVATION_BIT) > 0;
		mintedPublic = (ob & OB_PUBLIC_BIT) > 0;
	}
	function getKeekInfo(uint256 token) external view returns (
		address owner, uint32 transfers, uint32 block0, uint32 blocksHeld, 
		bool isLocked, uint16 tag, uint8 pref, uint256 unlockPrice
	) {
		unchecked {
			uint256 td = _tokenData[token];
			if (td == 0) revert InvalidInput();
			owner = address(uint160(td));
			transfers = uint32(td >> TD_TRANSFER_SHIFT);
			block0 = uint32(td >> TD_BLOCK_SHIFT);
			blocksHeld = uint32(block.number - block0);
			tag = uint16((td >> TD_TAG_SHIFT) & TD_TAG_MASK);
			pref = uint8((td >> TD_PREF_SHIFT) & TD_PREF_MASK);
			isLocked = _isLocked(td);
			if (isLocked) {
				unlockPrice = _tokenUnlock[token].price;
			}
		}
	}
	// note: this is 0-based
	function keeksFromSlice(uint256 offset, uint256 size) external view returns (bytes32[] memory keeks) {
		unchecked {
			uint256 max = _maxSupply;
			if (offset < max) { // require valid index
				size = min(offset + size, max) - offset; // truncate
			} else {
				size = 0; // invalid
			}
			keeks = new bytes32[](size);
			for (uint256 i; i < size; ) { // just dumb memcpy
				keeks[i++] = bytes32(_tokenData[++offset]); 
			}
		}
	}

	// approvals
	function _requireApprovedSender(address owner, uint256 token) private view {
		if (owner != msg.sender && !isApprovedForAll(owner, msg.sender) && _tokenApproval[token] != msg.sender) {
			revert NotAllowed();
		}
	}
	function isApprovedForAll(address owner, address operator) public view returns (bool) {
		return _operatorApprovals[owner][operator];
	}
	function setApprovalForAll(address operator, bool approved) onlyAllowedOperatorApproval(operator) external {
		if (operator == msg.sender) revert NotAllowed(); // owner is always approved
		_operatorApprovals[msg.sender][operator] = approved;
		emit ApprovalForAll(msg.sender, operator, approved);
	}
	function getApproved(uint256 token) external view returns (address) {
		if (_tokenData[token] == 0) revert InvalidInput(); // ERC721
		return _tokenApproval[token];
	}
	function approve(address operator, uint256 token) onlyAllowedOperatorApproval(operator) external {
		address owner = address(uint160(_tokenData[token]));
		if (owner != msg.sender && !isApprovedForAll(owner, msg.sender)) revert NotAllowed();
		_tokenApproval[token] = operator;
		emit Approval(owner, operator, token);
	}

	// helper
	function min(uint256 a, uint256 b) private pure returns (uint256) {
		return a < b ? a : b;
	}

}

File 2 of 12 : DefaultOperatorFilterer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {OperatorFilterer} from "./OperatorFilterer.sol";
import {CANONICAL_CORI_SUBSCRIPTION} from "./lib/Constants.sol";
/**
 * @title  DefaultOperatorFilterer
 * @notice Inherits from OperatorFilterer and automatically subscribes to the default OpenSea subscription.
 * @dev    Please note that if your token contract does not provide an owner with EIP-173, it must provide
 *         administration methods on the contract itself to interact with the registry otherwise the subscription
 *         will be locked to the options set during construction.
 */

abstract contract DefaultOperatorFilterer is OperatorFilterer {
    /// @dev The constructor that is called when the contract is being deployed.
    constructor() OperatorFilterer(CANONICAL_CORI_SUBSCRIPTION, true) {}
}

File 3 of 12 : IERC2981.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/IERC165.sol";

/**
 * @dev Interface for the NFT Royalty Standard.
 *
 * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
 * support for royalty payments across all NFT marketplaces and ecosystem participants.
 *
 * _Available since v4.5._
 */
interface IERC2981 is IERC165 {
    /**
     * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
     * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
     */
    function royaltyInfo(uint256 tokenId, uint256 salePrice)
        external
        view
        returns (address receiver, uint256 royaltyAmount);
}

File 4 of 12 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 5 of 12 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @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);
}

File 6 of 12 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 7 of 12 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 8 of 12 : Ownable.sol
// 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);
    }
}

File 9 of 12 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

address constant CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS = 0x000000000000AAeB6D7670E522A718067333cd4E;
address constant CANONICAL_CORI_SUBSCRIPTION = 0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6;

File 10 of 12 : OperatorFilterer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {IOperatorFilterRegistry} from "./IOperatorFilterRegistry.sol";
import {CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS} from "./lib/Constants.sol";
/**
 * @title  OperatorFilterer
 * @notice Abstract contract whose constructor automatically registers and optionally subscribes to or copies another
 *         registrant's entries in the OperatorFilterRegistry.
 * @dev    This smart contract is meant to be inherited by token contracts so they can use the following:
 *         - `onlyAllowedOperator` modifier for `transferFrom` and `safeTransferFrom` methods.
 *         - `onlyAllowedOperatorApproval` modifier for `approve` and `setApprovalForAll` methods.
 *         Please note that if your token contract does not provide an owner with EIP-173, it must provide
 *         administration methods on the contract itself to interact with the registry otherwise the subscription
 *         will be locked to the options set during construction.
 */

abstract contract OperatorFilterer {
    /// @dev Emitted when an operator is not allowed.
    error OperatorNotAllowed(address operator);

    IOperatorFilterRegistry public constant OPERATOR_FILTER_REGISTRY =
        IOperatorFilterRegistry(CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS);

    /// @dev The constructor that is called when the contract is being deployed.
    constructor(address subscriptionOrRegistrantToCopy, bool subscribe) {
        // If an inheriting token contract is deployed to a network without the registry deployed, the modifier
        // will not revert, but the contract will need to be registered with the registry once it is deployed in
        // order for the modifier to filter addresses.
        if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
            if (subscribe) {
                OPERATOR_FILTER_REGISTRY.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy);
            } else {
                if (subscriptionOrRegistrantToCopy != address(0)) {
                    OPERATOR_FILTER_REGISTRY.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy);
                } else {
                    OPERATOR_FILTER_REGISTRY.register(address(this));
                }
            }
        }
    }

    /**
     * @dev A helper function to check if an operator is allowed.
     */
    modifier onlyAllowedOperator(address from) virtual {
        // Allow spending tokens from addresses with balance
        // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred
        // from an EOA.
        if (from != msg.sender) {
            _checkFilterOperator(msg.sender);
        }
        _;
    }

    /**
     * @dev A helper function to check if an operator approval is allowed.
     */
    modifier onlyAllowedOperatorApproval(address operator) virtual {
        _checkFilterOperator(operator);
        _;
    }

    /**
     * @dev A helper function to check if an operator is allowed.
     */
    function _checkFilterOperator(address operator) internal view virtual {
        // Check registry code length to facilitate testing in environments without a deployed registry.
        if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
            // under normal circumstances, this function will revert rather than return false, but inheriting contracts
            // may specify their own OperatorFilterRegistry implementations, which may behave differently
            if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), operator)) {
                revert OperatorNotAllowed(operator);
            }
        }
    }
}

File 11 of 12 : Context.sol
// 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;
    }
}

File 12 of 12 : IOperatorFilterRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

interface IOperatorFilterRegistry {
    /**
     * @notice Returns true if operator is not filtered for a given token, either by address or codeHash. Also returns
     *         true if supplied registrant address is not registered.
     */
    function isOperatorAllowed(address registrant, address operator) external view returns (bool);

    /**
     * @notice Registers an address with the registry. May be called by address itself or by EIP-173 owner.
     */
    function register(address registrant) external;

    /**
     * @notice Registers an address with the registry and "subscribes" to another address's filtered operators and codeHashes.
     */
    function registerAndSubscribe(address registrant, address subscription) external;

    /**
     * @notice Registers an address with the registry and copies the filtered operators and codeHashes from another
     *         address without subscribing.
     */
    function registerAndCopyEntries(address registrant, address registrantToCopy) external;

    /**
     * @notice Unregisters an address with the registry and removes its subscription. May be called by address itself or by EIP-173 owner.
     *         Note that this does not remove any filtered addresses or codeHashes.
     *         Also note that any subscriptions to this registrant will still be active and follow the existing filtered addresses and codehashes.
     */
    function unregister(address addr) external;

    /**
     * @notice Update an operator address for a registered address - when filtered is true, the operator is filtered.
     */
    function updateOperator(address registrant, address operator, bool filtered) external;

    /**
     * @notice Update multiple operators for a registered address - when filtered is true, the operators will be filtered. Reverts on duplicates.
     */
    function updateOperators(address registrant, address[] calldata operators, bool filtered) external;

    /**
     * @notice Update a codeHash for a registered address - when filtered is true, the codeHash is filtered.
     */
    function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external;

    /**
     * @notice Update multiple codeHashes for a registered address - when filtered is true, the codeHashes will be filtered. Reverts on duplicates.
     */
    function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external;

    /**
     * @notice Subscribe an address to another registrant's filtered operators and codeHashes. Will remove previous
     *         subscription if present.
     *         Note that accounts with subscriptions may go on to subscribe to other accounts - in this case,
     *         subscriptions will not be forwarded. Instead the former subscription's existing entries will still be
     *         used.
     */
    function subscribe(address registrant, address registrantToSubscribe) external;

    /**
     * @notice Unsubscribe an address from its current subscribed registrant, and optionally copy its filtered operators and codeHashes.
     */
    function unsubscribe(address registrant, bool copyExistingEntries) external;

    /**
     * @notice Get the subscription address of a given registrant, if any.
     */
    function subscriptionOf(address addr) external returns (address registrant);

    /**
     * @notice Get the set of addresses subscribed to a given registrant.
     *         Note that order is not guaranteed as updates are made.
     */
    function subscribers(address registrant) external returns (address[] memory);

    /**
     * @notice Get the subscriber at a given index in the set of addresses subscribed to a given registrant.
     *         Note that order is not guaranteed as updates are made.
     */
    function subscriberAt(address registrant, uint256 index) external returns (address);

    /**
     * @notice Copy filtered operators and codeHashes from a different registrantToCopy to addr.
     */
    function copyEntriesOf(address registrant, address registrantToCopy) external;

    /**
     * @notice Returns true if operator is filtered by a given address or its subscription.
     */
    function isOperatorFiltered(address registrant, address operator) external returns (bool);

    /**
     * @notice Returns true if the hash of an address's code is filtered by a given address or its subscription.
     */
    function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool);

    /**
     * @notice Returns true if a codeHash is filtered by a given address or its subscription.
     */
    function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool);

    /**
     * @notice Returns a list of filtered operators for a given address or its subscription.
     */
    function filteredOperators(address addr) external returns (address[] memory);

    /**
     * @notice Returns the set of filtered codeHashes for a given address or its subscription.
     *         Note that order is not guaranteed as updates are made.
     */
    function filteredCodeHashes(address addr) external returns (bytes32[] memory);

    /**
     * @notice Returns the filtered operator at the given index of the set of filtered operators for a given address or
     *         its subscription.
     *         Note that order is not guaranteed as updates are made.
     */
    function filteredOperatorAt(address registrant, uint256 index) external returns (address);

    /**
     * @notice Returns the filtered codeHash at the given index of the list of filtered codeHashes for a given address or
     *         its subscription.
     *         Note that order is not guaranteed as updates are made.
     */
    function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32);

    /**
     * @notice Returns true if an address has registered
     */
    function isRegistered(address addr) external returns (bool);

    /**
     * @dev Convenience method to compute the code hash of an arbitrary contract
     */
    function codeHashOf(address addr) external returns (bytes32);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"InvalidInput","type":"error"},{"inputs":[],"name":"InvalidLockState","type":"error"},{"inputs":[],"name":"InvalidReceiver","type":"error"},{"inputs":[],"name":"NotAllowed","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotAllowed","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":false,"internalType":"uint256","name":"token","type":"uint256"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[],"name":"MerkleRootChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"token","type":"uint256"}],"name":"MetadataUpdate","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":false,"internalType":"uint256","name":"packed","type":"uint256"}],"name":"SetPref","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"token","type":"uint256"}],"name":"UnlockAttempt","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"token","type":"uint256"}],"name":"Unlocked","type":"event"},{"inputs":[],"name":"OPERATOR_FILTER_REGISTRY","outputs":[{"internalType":"contract IOperatorFilterRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_tokenURIContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_tokenURIPrefix","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_tokenURISuffix","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"recs","type":"uint256[]"}],"name":"airdropKeeks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"token","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":[{"internalType":"uint256","name":"token","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"token","type":"uint256"}],"name":"getKeekInfo","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"transfers","type":"uint32"},{"internalType":"uint32","name":"block0","type":"uint32"},{"internalType":"uint32","name":"blocksHeld","type":"uint32"},{"internalType":"bool","name":"isLocked","type":"bool"},{"internalType":"uint16","name":"tag","type":"uint16"},{"internalType":"uint8","name":"pref","type":"uint8"},{"internalType":"uint256","name":"unlockPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMintInfo","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"dropped","type":"uint256"},{"internalType":"uint256","name":"minted","type":"uint256"},{"internalType":"uint256","name":"publicMax","type":"uint256"},{"internalType":"bool","name":"prefsLocked","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"getOwnerInfo","outputs":[{"internalType":"uint16","name":"owned","type":"uint16"},{"internalType":"uint16","name":"minted","type":"uint16"},{"internalType":"uint256","name":"acquired","type":"uint256"},{"internalType":"bool","name":"mintedReservation","type":"bool"},{"internalType":"bool","name":"mintedPublic","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRoyaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"numer","type":"uint256"},{"internalType":"uint256","name":"denom","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"md","type":"uint256"},{"internalType":"address","name":"minter","type":"address"}],"name":"hasMinted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"token","type":"uint256"}],"name":"isKeekLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"}],"name":"keeksFromSlice","outputs":[{"internalType":"bytes32[]","name":"keeks","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"token","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"lockKeek","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockPrefs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"token","type":"uint256"},{"internalType":"string","name":"password","type":"string"}],"name":"makePasswordHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"uint256","name":"md","type":"uint256"},{"internalType":"uint256[]","name":"prefs","type":"uint256[]"}],"name":"mintKeeks","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"token","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"supply","type":"uint256"}],"name":"reduceSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"token","type":"uint256"}],"name":"rescueKeek","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"token","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":"token","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":"bytes32","name":"hash","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"priceWei","type":"uint256"}],"name":"setMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"token","type":"uint256"},{"internalType":"uint256","name":"pref","type":"uint256"}],"name":"setPref","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"max","type":"uint256"}],"name":"setPublicMax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"numer","type":"uint256"}],"name":"setRoyaltyInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"token","type":"uint256"},{"internalType":"uint256","name":"tag","type":"uint256"}],"name":"setTag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setTokenURIContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"prefix","type":"string"}],"name":"setTokenURIPrefix","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"suffix","type":"string"}],"name":"setTokenURISuffix","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"x","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"token","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"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":"token","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"token","type":"uint256"},{"internalType":"string","name":"password","type":"string"},{"internalType":"address","name":"transfer","type":"address"}],"name":"unlockKeek","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c0604052601d60809081527f476f6f64204d6f726e696e6720436166653a204b65656b75736175727300000060a0526006906200003e908262000375565b506040805180820190915260048152634b45454b60e01b602082015260079062000069908262000375565b5066d529ae9e860000600a55610d05600c55610183600d556040518060600160405280602481526020016200339d60249139601090620000aa908262000375565b50604080518082019091526005815264173539b7b760d91b6020820152601190620000d6908262000375565b50601280546001600160a01b03191673a050f07d0a880b7c9389a782250d6848ba43385417905561c3506013553480156200011057600080fd5b50733cc6cdda760b79bafa08df41ecfa224f810dceb66001620001333362000280565b6daaeb6d7670e522a718067333cd4e3b1562000278578015620001c657604051633e9f1edf60e11b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e90637d3e3dbe906044015b600060405180830381600087803b158015620001a757600080fd5b505af1158015620001bc573d6000803e3d6000fd5b5050505062000278565b6001600160a01b03821615620002175760405163a0af290360e01b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e9063a0af2903906044016200018c565b604051632210724360e11b81523060048201526daaeb6d7670e522a718067333cd4e90634420e48690602401600060405180830381600087803b1580156200025e57600080fd5b505af115801562000273573d6000803e3d6000fd5b505050505b505062000441565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620002fb57607f821691505b6020821081036200031c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200037057600081815260208120601f850160051c810160208610156200034b5750805b601f850160051c820191505b818110156200036c5782815560010162000357565b5050505b505050565b81516001600160401b03811115620003915762000391620002d0565b620003a981620003a28454620002e6565b8462000322565b602080601f831160018114620003e15760008415620003c85750858301515b600019600386901b1c1916600185901b1785556200036c565b600085815260208120601f198616915b828110156200041257888601518255948401946001909101908401620003f1565b5085821015620004315787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b612f4c80620004516000396000f3fe6080604052600436106102f85760003560e01c8063847309e11161019a578063c87b56dd116100e1578063e985e9c51161008a578063f161b23711610064578063f161b237146109bc578063f2fde38b146109dc578063f4a0a528146109fc57600080fd5b8063e985e9c514610933578063ec71f63a1461097c578063efe5b11a1461099c57600080fd5b8063d0520c23116100bb578063d0520c231461083f578063d385de8214610883578063e2e784d51461091357600080fd5b8063c87b56dd146107ea578063cbd0f21b1461080a578063cd2e7d431461082a57600080fd5b806399e0dd7c11610143578063a9852bfb1161011d578063a9852bfb1461078a578063b88d4fde146107aa578063c0d7c9f5146107ca57600080fd5b806399e0dd7c1461070e578063a22cb4651461072e578063a86a28d11461074e57600080fd5b80638da5cb5b116101745780638da5cb5b146106c857806393fde110146106e657806395d89b41146106f957600080fd5b8063847309e1146106755780638b86c4ee146106955780638c2b893e146106a857600080fd5b806341f434341161025e57806370a08231116102075780637cb64759116101e15780637cb6475914610615578063806234441461063557806382fc31471461065557600080fd5b806370a0823114610567578063715018a6146105875780637bc8567f1461059c57600080fd5b806359de91ef1161023857806359de91ef146105055780636352211e1461051a578063665660461461054757600080fd5b806341f434341461049657806342842e0e146104b8578063582a5e72146104d857600080fd5b80630c0b8ba3116102c057806323b872dd1161029a57806323b872dd146104225780632a55205a146104425780633ccfd60b1461048157600080fd5b80630c0b8ba3146103ce57806311b2df83146103e357806318160ddd1461040357600080fd5b806301ffc9a7146102fd578063037807331461033257806306fdde0314610352578063081812fc14610374578063095ea7b3146103ac575b600080fd5b34801561030957600080fd5b5061031d61031836600461267b565b610a1c565b60405190151581526020015b60405180910390f35b34801561033e57600080fd5b5061031d61034d3660046126b4565b610abf565b34801561035e57600080fd5b50610367610b00565b6040516103299190612727565b34801561038057600080fd5b5061039461038f36600461273a565b610b8e565b6040516001600160a01b039091168152602001610329565b3480156103b857600080fd5b506103cc6103c7366004612753565b610bd8565b005b3480156103da57600080fd5b50610367610ca9565b3480156103ef57600080fd5b506103cc6103fe36600461277d565b610cb6565b34801561040f57600080fd5b50600b545b604051908152602001610329565b34801561042e57600080fd5b506103cc61043d3660046127a9565b610db3565b34801561044e57600080fd5b5061046261045d3660046127e5565b610e0f565b604080516001600160a01b039093168352602083019190915201610329565b34801561048d57600080fd5b506103cc610e46565b3480156104a257600080fd5b506103946daaeb6d7670e522a718067333cd4e81565b3480156104c457600080fd5b506103cc6104d33660046127a9565b610fda565b3480156104e457600080fd5b506104f86104f33660046127e5565b610ff5565b6040516103299190612807565b34801561051157600080fd5b506103cc6110b4565b34801561052657600080fd5b5061039461053536600461273a565b60009081526002602052604090205490565b34801561055357600080fd5b506103cc61056236600461273a565b6110ef565b34801561057357600080fd5b5061041461058236600461284b565b6110fc565b34801561059357600080fd5b506103cc611145565b3480156105a857600080fd5b506105bc6105b736600461273a565b611159565b604080516001600160a01b03909916895263ffffffff97881660208a0152958716958801959095529490921660608601521515608085015261ffff1660a084015260ff90911660c083015260e082015261010001610329565b34801561062157600080fd5b506103cc61063036600461273a565b6111f9565b34801561064157600080fd5b506103cc61065036600461273a565b611232565b34801561066157600080fd5b506103cc61067036600461284b565b611284565b34801561068157600080fd5b506103cc61069036600461273a565b6112ae565b6103cc6106a3366004612933565b6113fd565b3480156106b457600080fd5b506103cc6106c33660046127e5565b61159c565b3480156106d457600080fd5b506000546001600160a01b0316610394565b6103cc6106f43660046129d6565b61169f565b34801561070557600080fd5b50610367611a68565b34801561071a57600080fd5b506103cc610729366004612a50565b611a75565b34801561073a57600080fd5b506103cc610749366004612ad0565b611a8a565b34801561075a57600080fd5b50601254601354604080516001600160a01b0390931683526020830191909152620f424090820152606001610329565b34801561079657600080fd5b506103cc6107a5366004612a50565b611b2a565b3480156107b657600080fd5b506103cc6107c5366004612b07565b611b3f565b3480156107d657600080fd5b506104146107e5366004612b83565b611c49565b3480156107f657600080fd5b5061036761080536600461273a565b611c7c565b34801561081657600080fd5b5061031d61082536600461273a565b611f35565b34801561083657600080fd5b50610367611f51565b34801561084b57600080fd5b50610854611f5e565b6040805196875260208701959095529385019290925260608401526080830152151560a082015260c001610329565b34801561088f57600080fd5b506108e161089e36600461284b565b6001600160a01b0316600090815260016020526040902054610fff80821692600c83901c90911691601a81901c9163010000008216151591630200000016151590565b6040805161ffff968716815295909416602086015292840191909152151560608301521515608082015260a001610329565b34801561091f57600080fd5b506103cc61092e366004612753565b611fa8565b34801561093f57600080fd5b5061031d61094e366004612bca565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561098857600080fd5b506103cc6109973660046127e5565b612011565b3480156109a857600080fd5b50600f54610394906001600160a01b031681565b3480156109c857600080fd5b506103cc6109d7366004612bf4565b612093565b3480156109e857600080fd5b506103cc6109f736600461284b565b6121a5565b348015610a0857600080fd5b506103cc610a1736600461273a565b61221e565b60006001600160e01b031982166301ffc9a760e01b1480610a4d57506001600160e01b031982166380ac58cd60e01b145b80610a6857506001600160e01b03198216635b5e139f60e01b145b80610a8357506001600160e01b0319821663152a902d60e11b145b80610a9e57506307f5828d60e41b6001600160e01b03198316145b80610ab95750632483248360e11b6001600160e01b03198316145b92915050565b6000600583901c8181610ad6576302000000610adc565b63010000005b6001600160a01b038516600090815260016020526040902054161191505092915050565b60068054610b0d90612c36565b80601f0160208091040260200160405190810160405280929190818152602001828054610b3990612c36565b8015610b865780601f10610b5b57610100808354040283529160200191610b86565b820191906000526020600020905b815481529060010190602001808311610b6957829003601f168201915b505050505081565b6000818152600260205260408120548103610bbc5760405163b4fa3fb360e01b815260040160405180910390fd5b506000908152600460205260409020546001600160a01b031690565b81610be28161222b565b6000828152600260205260409020546001600160a01b0381163314801590610c2e57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff16155b15610c4c57604051631eb49d6d60e11b815260040160405180910390fd5b60008381526004602052604080822080546001600160a01b0319166001600160a01b0388811691821790925591518693918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a450505050565b60118054610b0d90612c36565b600083815260026020526040902054600160ef1b811615610cea57604051630106530b60e21b815260040160405180910390fd5b610cf481856122e4565b8215610d28576040805180820182528381526020808201868152600088815260039092529290209051815590516001909101555b60008481526002602052604090819020600160ef1b83179055517f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a161190610d719086815260200190565b60405180910390a16040518481527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7906020015b60405180910390a150505050565b826001600160a01b0381163314610dcd57610dcd3361222b565b6001600160a01b038316610df457604051631e4ec46b60e01b815260040160405180910390fd5b610dfe84836122e4565b610e09848484612366565b50505050565b6012546013546001600160a01b0390911690600090620f424090610e339085612c80565b610e3d9190612c97565b90509250929050565b476000819003610e695760405163b4fa3fb360e01b815260040160405180910390fd5b6000610e76601483612c97565b60405190915073f29c7db01873db03d7de5d0f238b1e08d0c7edd89082156108fc029083906000818181858888f19350505050158015610eba573d6000803e3d6000fd5b50604051736a1e88b4ef7098347f078ebc4d8fbfc064defb8a9082156108fc029083906000818181858888f19350505050158015610efc573d6000803e3d6000fd5b5060405173db513d3d4bd419a7c3ad24e363b3b6e8ccacb67e90600183901b80156108fc02916000818181858888f19350505050158015610f41573d6000803e3d6000fd5b5060405173b23db186161ba869c06faed618d0a0263bdb75c390600283901b80156108fc02916000818181858888f19350505050158015610f86573d6000803e3d6000fd5b5073a050f07d0a880b7c9389a782250d6848ba4338546108fc610fad600384901b85612cb9565b6040518115909202916000818181858888f19350505050158015610fd5573d6000803e3d6000fd5b505050565b610fd583838360405180602001604052806000815250611b3f565b600c54606090808410156110185783611010848601836124df565b03925061101d565b600092505b8267ffffffffffffffff81111561103657611036612866565b60405190808252806020026020018201604052801561105f578160200160208202803683370190505b50915060005b838110156110ac576001948501600081815260026020526040902054845191968301929091859190811061109b5761109b612ccc565b602002602001018181525050611065565b505092915050565b6110bc6124f7565b60085460ff16156110e05760405163b4fa3fb360e01b815260040160405180910390fd5b6008805460ff19166001179055565b6110f76124f7565b600e55565b60006001600160a01b0382166111255760405163b4fa3fb360e01b815260040160405180910390fd5b506001600160a01b0316600090815260016020526040902054610fff1690565b61114d6124f7565b6111576000612551565b565b60008181526002602052604081205481908190819081908190819081908082036111965760405163b4fa3fb360e01b815260040160405180910390fd5b975060c088901c965060a088901c955063ffffffff86164303945060e088901c617fff16925060f088901c600f16915087600160ef1b81161515945084156111ed5760008a81526003602052604090206001015491505b50919395975091939597565b6112016124f7565b60098190556040517fd0f3723ea2283c278fd41187b7a45cc2c23de2dcab39487a38df33a9606bb75d90600090a150565b61123a6124f7565b600c54811061125c5760405163b4fa3fb360e01b815260040160405180910390fd5b600d5481101561127f5760405163b4fa3fb360e01b815260040160405180910390fd5b600c55565b61128c6124f7565b600f80546001600160a01b0319166001600160a01b0392909216919091179055565b6112b66124f7565b600081815260026020526040902054600160ef1b81166112e957604051630106530b60e21b815260040160405180910390fd5b6001600160a01b0381166000908152600560209081526040808320308452909152902054819060ff1615801561133657506000838152600460205260409020546001600160a01b03163014155b1561135457604051631eb49d6d60e11b815260040160405180910390fd5b60008381526003602090815260408083208381556001018390556002825291829020600160ef1b8518905590518481527ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f1842910160405180910390a16040518381527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a16001600160a01b0381163314610fd557610fd5813385612366565b600083815260026020526040902054600160ef1b811661143057604051630106530b60e21b815260040160405180910390fd5b8061143b81866122e4565b6000858152600360205260409020600181015480156114e557346000036114ae576114668787611c49565b8254146114a9576040518781527f20747090916c4c0f81f7c53c0d31f3bb051499ea01cbb8dfef8d2c7e2e246fce9060200160405180910390a150505050505050565b6114cf565b803410156114cf57604051630106530b60e21b815260040160405180910390fd5b6000878152600360205260408120818155600101555b60008781526002602052604090819020600160ef1b86189055517ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f18429061152e9089815260200190565b60405180910390a16040518781527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a16001600160a01b038516156115935761159383868960405180602001604052806000815250611b3f565b50505050505050565b60085460ff16156115c057604051631eb49d6d60e11b815260040160405180910390fd5b6101838211156115e357604051631eb49d6d60e11b815260040160405180910390fd5b60088110806115f25750600f81115b156116105760405163b4fa3fb360e01b815260040160405180910390fd5b61161a33836122e4565b60008281526002602052604090205460f081901c600f16801561165057604051631eb49d6d60e11b815260040160405180910390fd5b6000848152600260205260409081902060f085901b84179055517f7209687186d65a9ead6abaa81733dc70cfddfc5329c264b5b73ee87e50d1381b90610da590600c86901b8717815260200190565b3332146116de5760405162461bcd60e51b81526020600482015260086024820152676f6e6c7920656f6160c01b60448201526064015b60405180910390fd5b33600090815260016020526040812054600585901c919081831561170f575060018616151591506301000000611716565b5063020000005b818116156117575760405162461bcd60e51b815260206004820152600e60248201526d185b1c9958591e481b5a5b9d195960921b60448201526064016116d5565b90811790600087810361176d5750600e5461188b565b506040516bffffffffffffffffffffffff193360601b16602082015260348101889052600188901c600f169060009060540160405160208183030381529060405280519060200120905060005b8a81101561184b5760008c8c838181106117d6576117d6612ccc565b90506020020135905082811061181557604080516020810185905290810182905260600160405160208183030381529060405280519060200120611840565b6040805160208101839052908101849052606001604051602081830303815290604052805190602001205b9250506001016117ba565b5060095481146118895760405162461bcd60e51b81526020600482015260096024820152683130b210383937b7b360b91b60448201526064016116d5565b505b808611156118ca5760405162461bcd60e51b815260206004820152600c60248201526b626164207175616e7469747960a01b60448201526064016116d5565b600d54600c546000906118e090839003896124df565b90506000811161191f5760405162461bcd60e51b815260206004820152600a6024820152696d617820737570706c7960b01b60448201526064016116d5565b600a548102348111156119605760405162461bcd60e51b81526020600482015260096024820152686261642076616c756560b81b60448201526064016116d5565b600b805483019055828201600d553360009081526001602052604081206110018402880190555b82811015611a1d5783600101935060008815611a0957600f8c8c848181106119b1576119b1612ccc565b9050602002013516905060088110611a095760405160188b901b601084901b17600c83901b17861781527f7209687186d65a9ead6abaa81733dc70cfddfc5329c264b5b73ee87e50d1381b9060200160405180910390a15b611a148533836125a1565b50600101611987565b5034818103908214611a5857604051339082156108fc029083906000818181858888f19350505050158015611a56573d6000803e3d6000fd5b505b5050505050505050505050505050565b60078054610b0d90612c36565b611a7d6124f7565b6010610fd5828483612d30565b81611a948161222b565b336001600160a01b03841603611abd57604051631eb49d6d60e11b815260040160405180910390fd5b3360008181526005602090815260408083206001600160a01b03881680855290835292819020805460ff191687151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b611b326124f7565b6011610fd5828483612d30565b611b4a848484610db3565b6001600160a01b0383163b15610e0957604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290611b8c903390889087908790600401612df0565b6020604051808303816000875af1925050508015611bc7575060408051601f3d908101601f19168201909252611bc491810190612e2c565b60015b611c25573d808015611bf5576040519150601f19603f3d011682016040523d82523d6000602084013e611bfa565b606091505b508051600003611c1d57604051631e4ec46b60e01b815260040160405180910390fd5b805160208201fd5b6001600160e01b03198116630a85bd0160e11b14611c4257600080fd5b5050505050565b60008282604051602001611c5e929190612e49565b60405160208183030381529060405280519060200120905092915050565b600081815260026020526040812054606091819003611cae5760405163b4fa3fb360e01b815260040160405180910390fd5b600f546001600160a01b031615611d5257600f546001600160a01b03828116600090815260016020526040908190205490516308c02cf360e41b815260048101859052602481019190915283929190911690638c02cf3090604401600060405180830381865afa158015611d26573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d4e9190810190612e6f565b9250505b8151600003611f2f57600060108054611d6a90612c36565b80601f0160208091040260200160405190810160405280929190818152602001828054611d9690612c36565b8015611de35780601f10611db857610100808354040283529160200191611de3565b820191906000526020600020905b815481529060010190602001808311611dc657829003601f168201915b50505050509050600060118054611df990612c36565b80601f0160208091040260200160405190810160405280929190818152602001828054611e2590612c36565b8015611e725780601f10611e4757610100808354040283529160200191611e72565b820191906000526020600020905b815481529060010190602001808311611e5557829003601f168201915b50505050509050805182516004010167ffffffffffffffff811115611e9957611e99612866565b6040519080825280601f01601f191660200182016040528015611ec3576020820181803683370190505b50935083611ed181846125fe565b905060006064871015611ef557600a871015611eee576001611f09565b6002611f09565b6103e8871015611f06576003611f09565b60045b60ff169050611f19828883612626565b9150611f2582846125fe565b8690038652505050505b50919050565b600081815260026020526040812054600160ef1b161515610ab9565b60108054610b0d90612c36565b600a54600c54600d54600090819081908190611f7d9061018390612cb9565b925082600b54611f8d9190612cb9565b600e546008549798969791969495509360ff90911692509050565b611fb06124f7565b6001600160a01b03821615611fc857620f4240611fcb565b60005b811115611feb5760405163b4fa3fb360e01b815260040160405180910390fd5b601280546001600160a01b0319166001600160a01b039390931692909217909155601355565b617fff8111156120345760405163b4fa3fb360e01b815260040160405180910390fd5b60008281526002602052604090205461204d81846122e4565b60e081901c617fff168281036120765760405163b4fa3fb360e01b815260040160405180910390fd5b6000938452600260205260409093209190921860e01b9091189055565b61209b6124f7565b60005b818110156121865760008383838181106120ba576120ba612ccc565b602002919091013591508190506001600160a01b0381166120ee5760405163b4fa3fb360e01b815260040160405180910390fd5b60a082901c801580612101575061018381115b1561211f5760405163b4fa3fb360e01b815260040160405180910390fd5b6000818152600260205260409020541561214c57604051631eb49d6d60e11b815260040160405180910390fd5b612158818360006125a1565b506001600160a01b03166000908152600160208190526040909120805461100101905591909101905061209e565b5081819050600b600082825461219c9190612ee6565b90915550505050565b6121ad6124f7565b6001600160a01b0381166122125760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016116d5565b61221b81612551565b50565b6122266124f7565b600a55565b6daaeb6d7670e522a718067333cd4e3b1561221b57604051633185c44d60e21b81523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015612298573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122bc9190612ef9565b61221b57604051633b79c77360e21b81526001600160a01b03821660048201526024016116d5565b6001600160a01b038216331480159061232157506001600160a01b038216600090815260056020908152604080832033845290915290205460ff16155b801561234457506000818152600460205260409020546001600160a01b03163314155b1561236257604051631eb49d6d60e11b815260040160405180910390fd5b5050565b826001600160a01b0316826001600160a01b03160361239857604051631e4ec46b60e01b815260040160405180910390fd5b6000818152600260205260409020546001600160a01b03808216908516146123d357604051631eb49d6d60e11b815260040160405180910390fd5b600160ef1b8116156124185760405162461bcd60e51b815260206004820152600e60248201526d12d9595ac81a5cc8131bd8dad95960921b60448201526064016116d5565b600082815260046020908152604080832080546001600160a01b0319169055600282528083206001600160a01b0387811660c087811c600190810190911b63ffffffff60c01b164360a01b7fffff0000000000000000000000000000000000000000000000000000000000008a161717821790935590891680865291909352818420805460001901905582845281842080546304000001019055905185937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450505050565b60008183106124ee57816124f0565b825b9392505050565b6000546001600160a01b031633146111575760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016116d5565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000838152600260205260408082206001600160a01b0385164360a01b60f086901b60f489901b1717811790915590518592907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4505050565b80518201815b8184101561261f576020908101805194909101938452612604565b5092915050565b6000600382901b81805b8281101561265157600a8087049606603001811b9190911790600801612630565b50855190911b179190930190815292915050565b6001600160e01b03198116811461221b57600080fd5b60006020828403121561268d57600080fd5b81356124f081612665565b80356001600160a01b03811681146126af57600080fd5b919050565b600080604083850312156126c757600080fd5b82359150610e3d60208401612698565b60005b838110156126f25781810151838201526020016126da565b50506000910152565b600081518084526127138160208601602086016126d7565b601f01601f19169290920160200192915050565b6020815260006124f060208301846126fb565b60006020828403121561274c57600080fd5b5035919050565b6000806040838503121561276657600080fd5b61276f83612698565b946020939093013593505050565b60008060006060848603121561279257600080fd5b505081359360208301359350604090920135919050565b6000806000606084860312156127be57600080fd5b6127c784612698565b92506127d560208501612698565b9150604084013590509250925092565b600080604083850312156127f857600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b8181101561283f57835183529284019291840191600101612823565b50909695505050505050565b60006020828403121561285d57600080fd5b6124f082612698565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156128a5576128a5612866565b604052919050565b600067ffffffffffffffff8211156128c7576128c7612866565b50601f01601f191660200190565b60006128e86128e3846128ad565b61287c565b90508281528383830111156128fc57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261292457600080fd5b6124f0838335602085016128d5565b60008060006060848603121561294857600080fd5b83359250602084013567ffffffffffffffff81111561296657600080fd5b61297286828701612913565b92505061298160408501612698565b90509250925092565b60008083601f84011261299c57600080fd5b50813567ffffffffffffffff8111156129b457600080fd5b6020830191508360208260051b85010111156129cf57600080fd5b9250929050565b6000806000806000606086880312156129ee57600080fd5b853567ffffffffffffffff80821115612a0657600080fd5b612a1289838a0161298a565b9097509550602088013594506040880135915080821115612a3257600080fd5b50612a3f8882890161298a565b969995985093965092949392505050565b60008060208385031215612a6357600080fd5b823567ffffffffffffffff80821115612a7b57600080fd5b818501915085601f830112612a8f57600080fd5b813581811115612a9e57600080fd5b866020828501011115612ab057600080fd5b60209290920196919550909350505050565b801515811461221b57600080fd5b60008060408385031215612ae357600080fd5b612aec83612698565b91506020830135612afc81612ac2565b809150509250929050565b60008060008060808587031215612b1d57600080fd5b612b2685612698565b9350612b3460208601612698565b925060408501359150606085013567ffffffffffffffff811115612b5757600080fd5b8501601f81018713612b6857600080fd5b612b77878235602084016128d5565b91505092959194509250565b60008060408385031215612b9657600080fd5b82359150602083013567ffffffffffffffff811115612bb457600080fd5b612bc085828601612913565b9150509250929050565b60008060408385031215612bdd57600080fd5b612be683612698565b9150610e3d60208401612698565b60008060208385031215612c0757600080fd5b823567ffffffffffffffff811115612c1e57600080fd5b612c2a8582860161298a565b90969095509350505050565b600181811c90821680612c4a57607f821691505b602082108103611f2f57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610ab957610ab9612c6a565b600082612cb457634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610ab957610ab9612c6a565b634e487b7160e01b600052603260045260246000fd5b601f821115610fd557600081815260208120601f850160051c81016020861015612d095750805b601f850160051c820191505b81811015612d2857828155600101612d15565b505050505050565b67ffffffffffffffff831115612d4857612d48612866565b612d5c83612d568354612c36565b83612ce2565b6000601f841160018114612d905760008515612d785750838201355b600019600387901b1c1916600186901b178355611c42565b600083815260209020601f19861690835b82811015612dc15786850135825560209485019460019092019101612da1565b5086821015612dde5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152612e2260808301846126fb565b9695505050505050565b600060208284031215612e3e57600080fd5b81516124f081612665565b82815260008251612e618160208501602087016126d7565b919091016020019392505050565b600060208284031215612e8157600080fd5b815167ffffffffffffffff811115612e9857600080fd5b8201601f81018413612ea957600080fd5b8051612eb76128e3826128ad565b818152856020838501011115612ecc57600080fd5b612edd8260208301602086016126d7565b95945050505050565b80820180821115610ab957610ab9612c6a565b600060208284031215612f0b57600080fd5b81516124f081612ac256fea2646970667358221220a60f3af97e0b56804ae27195aedda3a1e146bdb509f7caa68f36fe46e791d27264736f6c6343000812003368747470733a2f2f6170692e676d636166652e696f2f6d657461646174612f6b65656b2f

Deployed Bytecode

0x6080604052600436106102f85760003560e01c8063847309e11161019a578063c87b56dd116100e1578063e985e9c51161008a578063f161b23711610064578063f161b237146109bc578063f2fde38b146109dc578063f4a0a528146109fc57600080fd5b8063e985e9c514610933578063ec71f63a1461097c578063efe5b11a1461099c57600080fd5b8063d0520c23116100bb578063d0520c231461083f578063d385de8214610883578063e2e784d51461091357600080fd5b8063c87b56dd146107ea578063cbd0f21b1461080a578063cd2e7d431461082a57600080fd5b806399e0dd7c11610143578063a9852bfb1161011d578063a9852bfb1461078a578063b88d4fde146107aa578063c0d7c9f5146107ca57600080fd5b806399e0dd7c1461070e578063a22cb4651461072e578063a86a28d11461074e57600080fd5b80638da5cb5b116101745780638da5cb5b146106c857806393fde110146106e657806395d89b41146106f957600080fd5b8063847309e1146106755780638b86c4ee146106955780638c2b893e146106a857600080fd5b806341f434341161025e57806370a08231116102075780637cb64759116101e15780637cb6475914610615578063806234441461063557806382fc31471461065557600080fd5b806370a0823114610567578063715018a6146105875780637bc8567f1461059c57600080fd5b806359de91ef1161023857806359de91ef146105055780636352211e1461051a578063665660461461054757600080fd5b806341f434341461049657806342842e0e146104b8578063582a5e72146104d857600080fd5b80630c0b8ba3116102c057806323b872dd1161029a57806323b872dd146104225780632a55205a146104425780633ccfd60b1461048157600080fd5b80630c0b8ba3146103ce57806311b2df83146103e357806318160ddd1461040357600080fd5b806301ffc9a7146102fd578063037807331461033257806306fdde0314610352578063081812fc14610374578063095ea7b3146103ac575b600080fd5b34801561030957600080fd5b5061031d61031836600461267b565b610a1c565b60405190151581526020015b60405180910390f35b34801561033e57600080fd5b5061031d61034d3660046126b4565b610abf565b34801561035e57600080fd5b50610367610b00565b6040516103299190612727565b34801561038057600080fd5b5061039461038f36600461273a565b610b8e565b6040516001600160a01b039091168152602001610329565b3480156103b857600080fd5b506103cc6103c7366004612753565b610bd8565b005b3480156103da57600080fd5b50610367610ca9565b3480156103ef57600080fd5b506103cc6103fe36600461277d565b610cb6565b34801561040f57600080fd5b50600b545b604051908152602001610329565b34801561042e57600080fd5b506103cc61043d3660046127a9565b610db3565b34801561044e57600080fd5b5061046261045d3660046127e5565b610e0f565b604080516001600160a01b039093168352602083019190915201610329565b34801561048d57600080fd5b506103cc610e46565b3480156104a257600080fd5b506103946daaeb6d7670e522a718067333cd4e81565b3480156104c457600080fd5b506103cc6104d33660046127a9565b610fda565b3480156104e457600080fd5b506104f86104f33660046127e5565b610ff5565b6040516103299190612807565b34801561051157600080fd5b506103cc6110b4565b34801561052657600080fd5b5061039461053536600461273a565b60009081526002602052604090205490565b34801561055357600080fd5b506103cc61056236600461273a565b6110ef565b34801561057357600080fd5b5061041461058236600461284b565b6110fc565b34801561059357600080fd5b506103cc611145565b3480156105a857600080fd5b506105bc6105b736600461273a565b611159565b604080516001600160a01b03909916895263ffffffff97881660208a0152958716958801959095529490921660608601521515608085015261ffff1660a084015260ff90911660c083015260e082015261010001610329565b34801561062157600080fd5b506103cc61063036600461273a565b6111f9565b34801561064157600080fd5b506103cc61065036600461273a565b611232565b34801561066157600080fd5b506103cc61067036600461284b565b611284565b34801561068157600080fd5b506103cc61069036600461273a565b6112ae565b6103cc6106a3366004612933565b6113fd565b3480156106b457600080fd5b506103cc6106c33660046127e5565b61159c565b3480156106d457600080fd5b506000546001600160a01b0316610394565b6103cc6106f43660046129d6565b61169f565b34801561070557600080fd5b50610367611a68565b34801561071a57600080fd5b506103cc610729366004612a50565b611a75565b34801561073a57600080fd5b506103cc610749366004612ad0565b611a8a565b34801561075a57600080fd5b50601254601354604080516001600160a01b0390931683526020830191909152620f424090820152606001610329565b34801561079657600080fd5b506103cc6107a5366004612a50565b611b2a565b3480156107b657600080fd5b506103cc6107c5366004612b07565b611b3f565b3480156107d657600080fd5b506104146107e5366004612b83565b611c49565b3480156107f657600080fd5b5061036761080536600461273a565b611c7c565b34801561081657600080fd5b5061031d61082536600461273a565b611f35565b34801561083657600080fd5b50610367611f51565b34801561084b57600080fd5b50610854611f5e565b6040805196875260208701959095529385019290925260608401526080830152151560a082015260c001610329565b34801561088f57600080fd5b506108e161089e36600461284b565b6001600160a01b0316600090815260016020526040902054610fff80821692600c83901c90911691601a81901c9163010000008216151591630200000016151590565b6040805161ffff968716815295909416602086015292840191909152151560608301521515608082015260a001610329565b34801561091f57600080fd5b506103cc61092e366004612753565b611fa8565b34801561093f57600080fd5b5061031d61094e366004612bca565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561098857600080fd5b506103cc6109973660046127e5565b612011565b3480156109a857600080fd5b50600f54610394906001600160a01b031681565b3480156109c857600080fd5b506103cc6109d7366004612bf4565b612093565b3480156109e857600080fd5b506103cc6109f736600461284b565b6121a5565b348015610a0857600080fd5b506103cc610a1736600461273a565b61221e565b60006001600160e01b031982166301ffc9a760e01b1480610a4d57506001600160e01b031982166380ac58cd60e01b145b80610a6857506001600160e01b03198216635b5e139f60e01b145b80610a8357506001600160e01b0319821663152a902d60e11b145b80610a9e57506307f5828d60e41b6001600160e01b03198316145b80610ab95750632483248360e11b6001600160e01b03198316145b92915050565b6000600583901c8181610ad6576302000000610adc565b63010000005b6001600160a01b038516600090815260016020526040902054161191505092915050565b60068054610b0d90612c36565b80601f0160208091040260200160405190810160405280929190818152602001828054610b3990612c36565b8015610b865780601f10610b5b57610100808354040283529160200191610b86565b820191906000526020600020905b815481529060010190602001808311610b6957829003601f168201915b505050505081565b6000818152600260205260408120548103610bbc5760405163b4fa3fb360e01b815260040160405180910390fd5b506000908152600460205260409020546001600160a01b031690565b81610be28161222b565b6000828152600260205260409020546001600160a01b0381163314801590610c2e57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff16155b15610c4c57604051631eb49d6d60e11b815260040160405180910390fd5b60008381526004602052604080822080546001600160a01b0319166001600160a01b0388811691821790925591518693918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a450505050565b60118054610b0d90612c36565b600083815260026020526040902054600160ef1b811615610cea57604051630106530b60e21b815260040160405180910390fd5b610cf481856122e4565b8215610d28576040805180820182528381526020808201868152600088815260039092529290209051815590516001909101555b60008481526002602052604090819020600160ef1b83179055517f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a161190610d719086815260200190565b60405180910390a16040518481527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7906020015b60405180910390a150505050565b826001600160a01b0381163314610dcd57610dcd3361222b565b6001600160a01b038316610df457604051631e4ec46b60e01b815260040160405180910390fd5b610dfe84836122e4565b610e09848484612366565b50505050565b6012546013546001600160a01b0390911690600090620f424090610e339085612c80565b610e3d9190612c97565b90509250929050565b476000819003610e695760405163b4fa3fb360e01b815260040160405180910390fd5b6000610e76601483612c97565b60405190915073f29c7db01873db03d7de5d0f238b1e08d0c7edd89082156108fc029083906000818181858888f19350505050158015610eba573d6000803e3d6000fd5b50604051736a1e88b4ef7098347f078ebc4d8fbfc064defb8a9082156108fc029083906000818181858888f19350505050158015610efc573d6000803e3d6000fd5b5060405173db513d3d4bd419a7c3ad24e363b3b6e8ccacb67e90600183901b80156108fc02916000818181858888f19350505050158015610f41573d6000803e3d6000fd5b5060405173b23db186161ba869c06faed618d0a0263bdb75c390600283901b80156108fc02916000818181858888f19350505050158015610f86573d6000803e3d6000fd5b5073a050f07d0a880b7c9389a782250d6848ba4338546108fc610fad600384901b85612cb9565b6040518115909202916000818181858888f19350505050158015610fd5573d6000803e3d6000fd5b505050565b610fd583838360405180602001604052806000815250611b3f565b600c54606090808410156110185783611010848601836124df565b03925061101d565b600092505b8267ffffffffffffffff81111561103657611036612866565b60405190808252806020026020018201604052801561105f578160200160208202803683370190505b50915060005b838110156110ac576001948501600081815260026020526040902054845191968301929091859190811061109b5761109b612ccc565b602002602001018181525050611065565b505092915050565b6110bc6124f7565b60085460ff16156110e05760405163b4fa3fb360e01b815260040160405180910390fd5b6008805460ff19166001179055565b6110f76124f7565b600e55565b60006001600160a01b0382166111255760405163b4fa3fb360e01b815260040160405180910390fd5b506001600160a01b0316600090815260016020526040902054610fff1690565b61114d6124f7565b6111576000612551565b565b60008181526002602052604081205481908190819081908190819081908082036111965760405163b4fa3fb360e01b815260040160405180910390fd5b975060c088901c965060a088901c955063ffffffff86164303945060e088901c617fff16925060f088901c600f16915087600160ef1b81161515945084156111ed5760008a81526003602052604090206001015491505b50919395975091939597565b6112016124f7565b60098190556040517fd0f3723ea2283c278fd41187b7a45cc2c23de2dcab39487a38df33a9606bb75d90600090a150565b61123a6124f7565b600c54811061125c5760405163b4fa3fb360e01b815260040160405180910390fd5b600d5481101561127f5760405163b4fa3fb360e01b815260040160405180910390fd5b600c55565b61128c6124f7565b600f80546001600160a01b0319166001600160a01b0392909216919091179055565b6112b66124f7565b600081815260026020526040902054600160ef1b81166112e957604051630106530b60e21b815260040160405180910390fd5b6001600160a01b0381166000908152600560209081526040808320308452909152902054819060ff1615801561133657506000838152600460205260409020546001600160a01b03163014155b1561135457604051631eb49d6d60e11b815260040160405180910390fd5b60008381526003602090815260408083208381556001018390556002825291829020600160ef1b8518905590518481527ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f1842910160405180910390a16040518381527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a16001600160a01b0381163314610fd557610fd5813385612366565b600083815260026020526040902054600160ef1b811661143057604051630106530b60e21b815260040160405180910390fd5b8061143b81866122e4565b6000858152600360205260409020600181015480156114e557346000036114ae576114668787611c49565b8254146114a9576040518781527f20747090916c4c0f81f7c53c0d31f3bb051499ea01cbb8dfef8d2c7e2e246fce9060200160405180910390a150505050505050565b6114cf565b803410156114cf57604051630106530b60e21b815260040160405180910390fd5b6000878152600360205260408120818155600101555b60008781526002602052604090819020600160ef1b86189055517ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f18429061152e9089815260200190565b60405180910390a16040518781527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a16001600160a01b038516156115935761159383868960405180602001604052806000815250611b3f565b50505050505050565b60085460ff16156115c057604051631eb49d6d60e11b815260040160405180910390fd5b6101838211156115e357604051631eb49d6d60e11b815260040160405180910390fd5b60088110806115f25750600f81115b156116105760405163b4fa3fb360e01b815260040160405180910390fd5b61161a33836122e4565b60008281526002602052604090205460f081901c600f16801561165057604051631eb49d6d60e11b815260040160405180910390fd5b6000848152600260205260409081902060f085901b84179055517f7209687186d65a9ead6abaa81733dc70cfddfc5329c264b5b73ee87e50d1381b90610da590600c86901b8717815260200190565b3332146116de5760405162461bcd60e51b81526020600482015260086024820152676f6e6c7920656f6160c01b60448201526064015b60405180910390fd5b33600090815260016020526040812054600585901c919081831561170f575060018616151591506301000000611716565b5063020000005b818116156117575760405162461bcd60e51b815260206004820152600e60248201526d185b1c9958591e481b5a5b9d195960921b60448201526064016116d5565b90811790600087810361176d5750600e5461188b565b506040516bffffffffffffffffffffffff193360601b16602082015260348101889052600188901c600f169060009060540160405160208183030381529060405280519060200120905060005b8a81101561184b5760008c8c838181106117d6576117d6612ccc565b90506020020135905082811061181557604080516020810185905290810182905260600160405160208183030381529060405280519060200120611840565b6040805160208101839052908101849052606001604051602081830303815290604052805190602001205b9250506001016117ba565b5060095481146118895760405162461bcd60e51b81526020600482015260096024820152683130b210383937b7b360b91b60448201526064016116d5565b505b808611156118ca5760405162461bcd60e51b815260206004820152600c60248201526b626164207175616e7469747960a01b60448201526064016116d5565b600d54600c546000906118e090839003896124df565b90506000811161191f5760405162461bcd60e51b815260206004820152600a6024820152696d617820737570706c7960b01b60448201526064016116d5565b600a548102348111156119605760405162461bcd60e51b81526020600482015260096024820152686261642076616c756560b81b60448201526064016116d5565b600b805483019055828201600d553360009081526001602052604081206110018402880190555b82811015611a1d5783600101935060008815611a0957600f8c8c848181106119b1576119b1612ccc565b9050602002013516905060088110611a095760405160188b901b601084901b17600c83901b17861781527f7209687186d65a9ead6abaa81733dc70cfddfc5329c264b5b73ee87e50d1381b9060200160405180910390a15b611a148533836125a1565b50600101611987565b5034818103908214611a5857604051339082156108fc029083906000818181858888f19350505050158015611a56573d6000803e3d6000fd5b505b5050505050505050505050505050565b60078054610b0d90612c36565b611a7d6124f7565b6010610fd5828483612d30565b81611a948161222b565b336001600160a01b03841603611abd57604051631eb49d6d60e11b815260040160405180910390fd5b3360008181526005602090815260408083206001600160a01b03881680855290835292819020805460ff191687151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b611b326124f7565b6011610fd5828483612d30565b611b4a848484610db3565b6001600160a01b0383163b15610e0957604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290611b8c903390889087908790600401612df0565b6020604051808303816000875af1925050508015611bc7575060408051601f3d908101601f19168201909252611bc491810190612e2c565b60015b611c25573d808015611bf5576040519150601f19603f3d011682016040523d82523d6000602084013e611bfa565b606091505b508051600003611c1d57604051631e4ec46b60e01b815260040160405180910390fd5b805160208201fd5b6001600160e01b03198116630a85bd0160e11b14611c4257600080fd5b5050505050565b60008282604051602001611c5e929190612e49565b60405160208183030381529060405280519060200120905092915050565b600081815260026020526040812054606091819003611cae5760405163b4fa3fb360e01b815260040160405180910390fd5b600f546001600160a01b031615611d5257600f546001600160a01b03828116600090815260016020526040908190205490516308c02cf360e41b815260048101859052602481019190915283929190911690638c02cf3090604401600060405180830381865afa158015611d26573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d4e9190810190612e6f565b9250505b8151600003611f2f57600060108054611d6a90612c36565b80601f0160208091040260200160405190810160405280929190818152602001828054611d9690612c36565b8015611de35780601f10611db857610100808354040283529160200191611de3565b820191906000526020600020905b815481529060010190602001808311611dc657829003601f168201915b50505050509050600060118054611df990612c36565b80601f0160208091040260200160405190810160405280929190818152602001828054611e2590612c36565b8015611e725780601f10611e4757610100808354040283529160200191611e72565b820191906000526020600020905b815481529060010190602001808311611e5557829003601f168201915b50505050509050805182516004010167ffffffffffffffff811115611e9957611e99612866565b6040519080825280601f01601f191660200182016040528015611ec3576020820181803683370190505b50935083611ed181846125fe565b905060006064871015611ef557600a871015611eee576001611f09565b6002611f09565b6103e8871015611f06576003611f09565b60045b60ff169050611f19828883612626565b9150611f2582846125fe565b8690038652505050505b50919050565b600081815260026020526040812054600160ef1b161515610ab9565b60108054610b0d90612c36565b600a54600c54600d54600090819081908190611f7d9061018390612cb9565b925082600b54611f8d9190612cb9565b600e546008549798969791969495509360ff90911692509050565b611fb06124f7565b6001600160a01b03821615611fc857620f4240611fcb565b60005b811115611feb5760405163b4fa3fb360e01b815260040160405180910390fd5b601280546001600160a01b0319166001600160a01b039390931692909217909155601355565b617fff8111156120345760405163b4fa3fb360e01b815260040160405180910390fd5b60008281526002602052604090205461204d81846122e4565b60e081901c617fff168281036120765760405163b4fa3fb360e01b815260040160405180910390fd5b6000938452600260205260409093209190921860e01b9091189055565b61209b6124f7565b60005b818110156121865760008383838181106120ba576120ba612ccc565b602002919091013591508190506001600160a01b0381166120ee5760405163b4fa3fb360e01b815260040160405180910390fd5b60a082901c801580612101575061018381115b1561211f5760405163b4fa3fb360e01b815260040160405180910390fd5b6000818152600260205260409020541561214c57604051631eb49d6d60e11b815260040160405180910390fd5b612158818360006125a1565b506001600160a01b03166000908152600160208190526040909120805461100101905591909101905061209e565b5081819050600b600082825461219c9190612ee6565b90915550505050565b6121ad6124f7565b6001600160a01b0381166122125760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016116d5565b61221b81612551565b50565b6122266124f7565b600a55565b6daaeb6d7670e522a718067333cd4e3b1561221b57604051633185c44d60e21b81523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015612298573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122bc9190612ef9565b61221b57604051633b79c77360e21b81526001600160a01b03821660048201526024016116d5565b6001600160a01b038216331480159061232157506001600160a01b038216600090815260056020908152604080832033845290915290205460ff16155b801561234457506000818152600460205260409020546001600160a01b03163314155b1561236257604051631eb49d6d60e11b815260040160405180910390fd5b5050565b826001600160a01b0316826001600160a01b03160361239857604051631e4ec46b60e01b815260040160405180910390fd5b6000818152600260205260409020546001600160a01b03808216908516146123d357604051631eb49d6d60e11b815260040160405180910390fd5b600160ef1b8116156124185760405162461bcd60e51b815260206004820152600e60248201526d12d9595ac81a5cc8131bd8dad95960921b60448201526064016116d5565b600082815260046020908152604080832080546001600160a01b0319169055600282528083206001600160a01b0387811660c087811c600190810190911b63ffffffff60c01b164360a01b7fffff0000000000000000000000000000000000000000000000000000000000008a161717821790935590891680865291909352818420805460001901905582845281842080546304000001019055905185937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450505050565b60008183106124ee57816124f0565b825b9392505050565b6000546001600160a01b031633146111575760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016116d5565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000838152600260205260408082206001600160a01b0385164360a01b60f086901b60f489901b1717811790915590518592907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4505050565b80518201815b8184101561261f576020908101805194909101938452612604565b5092915050565b6000600382901b81805b8281101561265157600a8087049606603001811b9190911790600801612630565b50855190911b179190930190815292915050565b6001600160e01b03198116811461221b57600080fd5b60006020828403121561268d57600080fd5b81356124f081612665565b80356001600160a01b03811681146126af57600080fd5b919050565b600080604083850312156126c757600080fd5b82359150610e3d60208401612698565b60005b838110156126f25781810151838201526020016126da565b50506000910152565b600081518084526127138160208601602086016126d7565b601f01601f19169290920160200192915050565b6020815260006124f060208301846126fb565b60006020828403121561274c57600080fd5b5035919050565b6000806040838503121561276657600080fd5b61276f83612698565b946020939093013593505050565b60008060006060848603121561279257600080fd5b505081359360208301359350604090920135919050565b6000806000606084860312156127be57600080fd5b6127c784612698565b92506127d560208501612698565b9150604084013590509250925092565b600080604083850312156127f857600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b8181101561283f57835183529284019291840191600101612823565b50909695505050505050565b60006020828403121561285d57600080fd5b6124f082612698565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156128a5576128a5612866565b604052919050565b600067ffffffffffffffff8211156128c7576128c7612866565b50601f01601f191660200190565b60006128e86128e3846128ad565b61287c565b90508281528383830111156128fc57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261292457600080fd5b6124f0838335602085016128d5565b60008060006060848603121561294857600080fd5b83359250602084013567ffffffffffffffff81111561296657600080fd5b61297286828701612913565b92505061298160408501612698565b90509250925092565b60008083601f84011261299c57600080fd5b50813567ffffffffffffffff8111156129b457600080fd5b6020830191508360208260051b85010111156129cf57600080fd5b9250929050565b6000806000806000606086880312156129ee57600080fd5b853567ffffffffffffffff80821115612a0657600080fd5b612a1289838a0161298a565b9097509550602088013594506040880135915080821115612a3257600080fd5b50612a3f8882890161298a565b969995985093965092949392505050565b60008060208385031215612a6357600080fd5b823567ffffffffffffffff80821115612a7b57600080fd5b818501915085601f830112612a8f57600080fd5b813581811115612a9e57600080fd5b866020828501011115612ab057600080fd5b60209290920196919550909350505050565b801515811461221b57600080fd5b60008060408385031215612ae357600080fd5b612aec83612698565b91506020830135612afc81612ac2565b809150509250929050565b60008060008060808587031215612b1d57600080fd5b612b2685612698565b9350612b3460208601612698565b925060408501359150606085013567ffffffffffffffff811115612b5757600080fd5b8501601f81018713612b6857600080fd5b612b77878235602084016128d5565b91505092959194509250565b60008060408385031215612b9657600080fd5b82359150602083013567ffffffffffffffff811115612bb457600080fd5b612bc085828601612913565b9150509250929050565b60008060408385031215612bdd57600080fd5b612be683612698565b9150610e3d60208401612698565b60008060208385031215612c0757600080fd5b823567ffffffffffffffff811115612c1e57600080fd5b612c2a8582860161298a565b90969095509350505050565b600181811c90821680612c4a57607f821691505b602082108103611f2f57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610ab957610ab9612c6a565b600082612cb457634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610ab957610ab9612c6a565b634e487b7160e01b600052603260045260246000fd5b601f821115610fd557600081815260208120601f850160051c81016020861015612d095750805b601f850160051c820191505b81811015612d2857828155600101612d15565b505050505050565b67ffffffffffffffff831115612d4857612d48612866565b612d5c83612d568354612c36565b83612ce2565b6000601f841160018114612d905760008515612d785750838201355b600019600387901b1c1916600186901b178355611c42565b600083815260209020601f19861690835b82811015612dc15786850135825560209485019460019092019101612da1565b5086821015612dde5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152612e2260808301846126fb565b9695505050505050565b600060208284031215612e3e57600080fd5b81516124f081612665565b82815260008251612e618160208501602087016126d7565b919091016020019392505050565b600060208284031215612e8157600080fd5b815167ffffffffffffffff811115612e9857600080fd5b8201601f81018413612ea957600080fd5b8051612eb76128e3826128ad565b818152856020838501011115612ecc57600080fd5b612edd8260208301602086016126d7565b95945050505050565b80820180821115610ab957610ab9612c6a565b600060208284031215612f0b57600080fd5b81516124f081612ac256fea2646970667358221220a60f3af97e0b56804ae27195aedda3a1e146bdb509f7caa68f36fe46e791d27264736f6c63430008120033

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.