// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
address constant CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS = 0x000000000000AAeB6D7670E522A718067333cd4E;
address constant CANONICAL_CORI_SUBSCRIPTION = 0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6;
// 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;
}
}
// 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) {}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.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);
}
// 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);
}
// 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);
}
// 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);
}
// 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);
}
/* 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/contracts@4.8.2/access/Ownable.sol";
import {IERC165} from "@openzeppelin/contracts@4.8.2/utils/introspection/IERC165.sol";
import {IERC721} from "@openzeppelin/contracts@4.8.2/token/ERC721/IERC721.sol";
import {IERC721Metadata} from "@openzeppelin/contracts@4.8.2/token/ERC721/extensions/IERC721Metadata.sol";
import {IERC721Receiver} from "@openzeppelin/contracts@4.8.2/token/ERC721/IERC721Receiver.sol";
import {IERC2981} from "@openzeppelin/contracts@4.8.2/interfaces/IERC2981.sol";
import {DefaultOperatorFilterer} from "operator-filter-registry@1.4.1/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;
}
}
// 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);
}
}
}
}
// 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);
}
}
{
"compilationTarget": {
"KEEK.sol": "KEEK"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 333
},
"remappings": []
}
[{"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"}]