文件 1 的 12:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 2 的 12:ERC721A.sol
pragma solidity ^0.8.4;
import './IERC721A.sol';
interface ERC721A__IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
contract ERC721A is IERC721A {
struct TokenApprovalRef {
address value;
}
uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
uint256 private constant _BITPOS_NUMBER_MINTED = 64;
uint256 private constant _BITPOS_NUMBER_BURNED = 128;
uint256 private constant _BITPOS_AUX = 192;
uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
uint256 private constant _BITPOS_START_TIMESTAMP = 160;
uint256 private constant _BITMASK_BURNED = 1 << 224;
uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
uint256 private constant _BITPOS_EXTRA_DATA = 232;
uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
uint256 private _currentIndex;
uint256 private _burnCounter;
string private _name;
string private _symbol;
mapping(uint256 => uint256) private _packedOwnerships;
mapping(address => uint256) private _packedAddressData;
mapping(uint256 => TokenApprovalRef) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
_currentIndex = _startTokenId();
}
function _startTokenId() internal view virtual returns (uint256) {
return 0;
}
function _nextTokenId() internal view virtual returns (uint256) {
return _currentIndex;
}
function totalSupply() public view virtual override returns (uint256) {
unchecked {
return _currentIndex - _burnCounter - _startTokenId();
}
}
function _totalMinted() internal view virtual returns (uint256) {
unchecked {
return _currentIndex - _startTokenId();
}
}
function _totalBurned() internal view virtual returns (uint256) {
return _burnCounter;
}
function balanceOf(address owner) public view virtual override returns (uint256) {
if (owner == address(0)) revert BalanceQueryForZeroAddress();
return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
}
function _numberMinted(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
function _numberBurned(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
function _getAux(address owner) internal view returns (uint64) {
return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
}
function _setAux(address owner, uint64 aux) internal virtual {
uint256 packed = _packedAddressData[owner];
uint256 auxCasted;
assembly {
auxCasted := aux
}
packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
_packedAddressData[owner] = packed;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == 0x01ffc9a7 ||
interfaceId == 0x80ac58cd ||
interfaceId == 0x5b5e139f;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
string memory baseURI = _baseURI();
return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
}
function _baseURI() internal view virtual returns (string memory) {
return '';
}
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
return address(uint160(_packedOwnershipOf(tokenId)));
}
function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnershipOf(tokenId));
}
function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnerships[index]);
}
function _initializeOwnershipAt(uint256 index) internal virtual {
if (_packedOwnerships[index] == 0) {
_packedOwnerships[index] = _packedOwnershipOf(index);
}
}
function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) {
uint256 curr = tokenId;
unchecked {
if (_startTokenId() <= curr)
if (curr < _currentIndex) {
uint256 packed = _packedOwnerships[curr];
if (packed & _BITMASK_BURNED == 0) {
while (packed == 0) {
packed = _packedOwnerships[--curr];
}
return packed;
}
}
}
revert OwnerQueryForNonexistentToken();
}
function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
ownership.addr = address(uint160(packed));
ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
ownership.burned = packed & _BITMASK_BURNED != 0;
ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
}
function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
assembly {
owner := and(owner, _BITMASK_ADDRESS)
result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
}
}
function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
assembly {
result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
}
}
function approve(address to, uint256 tokenId) public payable virtual override {
address owner = ownerOf(tokenId);
if (_msgSenderERC721A() != owner)
if (!isApprovedForAll(owner, _msgSenderERC721A())) {
revert ApprovalCallerNotOwnerNorApproved();
}
_tokenApprovals[tokenId].value = to;
emit Approval(owner, to, tokenId);
}
function getApproved(uint256 tokenId) public view virtual override returns (address) {
if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
return _tokenApprovals[tokenId].value;
}
function setApprovalForAll(address operator, bool approved) public virtual override {
_operatorApprovals[_msgSenderERC721A()][operator] = approved;
emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
}
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return
_startTokenId() <= tokenId &&
tokenId < _currentIndex &&
_packedOwnerships[tokenId] & _BITMASK_BURNED == 0;
}
function _isSenderApprovedOrOwner(
address approvedAddress,
address owner,
address msgSender
) private pure returns (bool result) {
assembly {
owner := and(owner, _BITMASK_ADDRESS)
msgSender := and(msgSender, _BITMASK_ADDRESS)
result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
}
}
function _getApprovedSlotAndAddress(uint256 tokenId)
private
view
returns (uint256 approvedAddressSlot, address approvedAddress)
{
TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
assembly {
approvedAddressSlot := tokenApproval.slot
approvedAddress := sload(approvedAddressSlot)
}
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
if (to == address(0)) revert TransferToZeroAddress();
_beforeTokenTransfers(from, to, tokenId, 1);
assembly {
if approvedAddress {
sstore(approvedAddressSlot, 0)
}
}
unchecked {
--_packedAddressData[from];
++_packedAddressData[to];
_packedOwnerships[tokenId] = _packOwnershipData(
to,
_BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
);
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
if (_packedOwnerships[nextTokenId] == 0) {
if (nextTokenId != _currentIndex) {
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, to, tokenId);
_afterTokenTransfers(from, to, tokenId, 1);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
safeTransferFrom(from, to, tokenId, '');
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public payable virtual override {
transferFrom(from, to, tokenId);
if (to.code.length != 0)
if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
}
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
function _checkContractOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
bytes4 retval
) {
return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert TransferToNonERC721ReceiverImplementer();
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
function _mint(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (quantity == 0) revert MintZeroQuantity();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
unchecked {
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
uint256 toMasked;
uint256 end = startTokenId + quantity;
assembly {
toMasked := and(to, _BITMASK_ADDRESS)
log4(
0,
0,
_TRANSFER_EVENT_SIGNATURE,
0,
toMasked,
startTokenId
)
for {
let tokenId := add(startTokenId, 1)
} iszero(eq(tokenId, end)) {
tokenId := add(tokenId, 1)
} {
log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
}
}
if (toMasked == 0) revert MintToZeroAddress();
_currentIndex = end;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
function _mintERC2309(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (to == address(0)) revert MintToZeroAddress();
if (quantity == 0) revert MintZeroQuantity();
if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
unchecked {
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
_currentIndex = startTokenId + quantity;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
function _safeMint(
address to,
uint256 quantity,
bytes memory _data
) internal virtual {
_mint(to, quantity);
unchecked {
if (to.code.length != 0) {
uint256 end = _currentIndex;
uint256 index = end - quantity;
do {
if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
} while (index < end);
if (_currentIndex != end) revert();
}
}
}
function _safeMint(address to, uint256 quantity) internal virtual {
_safeMint(to, quantity, '');
}
function _burn(uint256 tokenId) internal virtual {
_burn(tokenId, false);
}
function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
address from = address(uint160(prevOwnershipPacked));
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
if (approvalCheck) {
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
}
_beforeTokenTransfers(from, address(0), tokenId, 1);
assembly {
if approvedAddress {
sstore(approvedAddressSlot, 0)
}
}
unchecked {
_packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
_packedOwnerships[tokenId] = _packOwnershipData(
from,
(_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
);
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
if (_packedOwnerships[nextTokenId] == 0) {
if (nextTokenId != _currentIndex) {
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
unchecked {
_burnCounter++;
}
}
function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
uint256 packed = _packedOwnerships[index];
if (packed == 0) revert OwnershipNotInitializedForExtraData();
uint256 extraDataCasted;
assembly {
extraDataCasted := extraData
}
packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
_packedOwnerships[index] = packed;
}
function _extraData(
address from,
address to,
uint24 previousExtraData
) internal view virtual returns (uint24) {}
function _nextExtraData(
address from,
address to,
uint256 prevOwnershipPacked
) private view returns (uint256) {
uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
}
function _msgSenderERC721A() internal view virtual returns (address) {
return msg.sender;
}
function _toString(uint256 value) internal pure virtual returns (string memory str) {
assembly {
let m := add(mload(0x40), 0xa0)
mstore(0x40, m)
str := sub(m, 0x20)
mstore(str, 0)
let end := str
for { let temp := value } 1 {} {
str := sub(str, 1)
mstore8(str, add(48, mod(temp, 10)))
temp := div(temp, 10)
if iszero(temp) { break }
}
let length := sub(end, str)
str := sub(str, 0x20)
mstore(str, length)
}
}
}
文件 3 的 12:IERC721A.sol
pragma solidity ^0.8.4;
interface IERC721A {
error ApprovalCallerNotOwnerNorApproved();
error ApprovalQueryForNonexistentToken();
error BalanceQueryForZeroAddress();
error MintToZeroAddress();
error MintZeroQuantity();
error OwnerQueryForNonexistentToken();
error TransferCallerNotOwnerNorApproved();
error TransferFromIncorrectOwner();
error TransferToNonERC721ReceiverImplementer();
error TransferToZeroAddress();
error URIQueryForNonexistentToken();
error MintERC2309QuantityExceedsLimit();
error OwnershipNotInitializedForExtraData();
struct TokenOwnership {
address addr;
uint64 startTimestamp;
bool burned;
uint24 extraData;
}
function totalSupply() external view returns (uint256);
function supportsInterface(bytes4 interfaceId) external view returns (bool);
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external payable;
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external payable;
function transferFrom(
address from,
address to,
uint256 tokenId
) external payable;
function approve(address to, uint256 tokenId) external payable;
function setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}
文件 4 的 12:ITinyFrogRenderer.sol
pragma solidity ^0.8.0;
interface ITinyFrogRenderer{
function getSVG(uint256 seed, bool showBasedPlatform) external view returns (string memory);
function getUnrevealedSVG(uint256 seed) external view returns (string memory);
function getDeadSVG(uint256 seed) external view returns (string memory);
function getTraitsMetadata(uint256 seed, bool showBasedPlatform) external view returns (string memory);
}
文件 5 的 12:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1, "Math: mulDiv overflow");
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
文件 6 的 12:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 7 的 12:SignedMath.sol
pragma solidity ^0.8.0;
library SignedMath {
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
function average(int256 a, int256 b) internal pure returns (int256) {
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
function abs(int256 n) internal pure returns (uint256) {
unchecked {
return uint256(n >= 0 ? n : -n);
}
}
}
文件 8 的 12:Strings.sol
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
文件 9 的 12:TinyFrog.sol
pragma solidity ^0.8.4;
import "erc721a/contracts/ERC721A.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import 'base64-sol/base64.sol';
import "./ITinyFrogRenderer.sol";
import "./TinyFrogRenderer.sol";
interface IERC4906 {
event MetadataUpdate(uint256 _tokenId);
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
}
contract TinyFrog is TinyFrogRenderer, ERC721A, IERC4906, Ownable {
uint256 public MAX_TOKEN_SUPPLY = 1000;
uint256[] public mintSupplyLimits = [0, 250, 500, 750];
uint256[] public mintPricing = [0.005 ether, 0.01 ether, 0.015 ether, 0.02 ether];
enum MintStatus {
CLOSED,
PUBLIC
}
MintStatus public mintStatus = MintStatus.CLOSED;
uint256 public maxTokensOwnableInWallet = 25;
bool public revealed = false;
bool public morphEnabled = false;
bool public boilEnabled = false;
bool public soulbindEnabled = false;
mapping(uint256 => uint256) public seeds;
mapping(uint256 => bool) public soulbound;
mapping(uint256 => bool) public dead;
ITinyFrogRenderer public contractRenderer;
event TinyFrogBoiled(uint256 indexed tokenId);
event TinyFrogMorphed(uint256 indexed tokenId);
event TinyFrogSoulbound(uint256 indexed tokenId);
event TinyFrogDied(uint256 indexed tokenId);
event TokenLocked(uint256 indexed tokenId, address indexed approvedContract);
event Lock(address indexed unlocker, uint256 indexed id);
error TinyFrogIsSoulbound(uint256 tokenId);
constructor() ERC721A("Tiny Based Frogs", "TINYFROG") {
contractRenderer = ITinyFrogRenderer(this);
}
modifier verifyTokenId(uint256 tokenId) {
require(tokenId >= _startTokenId() && tokenId <= _totalMinted(), "Invalid tokenId");
_;
}
modifier onlyApprovedOrOwner(uint256 tokenId) {
require(
_ownershipOf(tokenId).addr == _msgSender() ||
getApproved(tokenId) == _msgSender(),
"Not approved nor owner"
);
_;
}
modifier verifySupply(uint256 numToMint) {
require(numToMint > 0, "Mint at least 1");
require(_totalMinted() + numToMint <= MAX_TOKEN_SUPPLY, "Overcap");
_;
}
function _saveNewRandomSeed(uint256 tokenId) private {
seeds[tokenId] = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), tokenId, msg.sender)));
}
function boilFrog(uint256 tokenId) external onlyApprovedOrOwner(tokenId) {
require(boilEnabled == true);
_burn(tokenId);
dead[tokenId] = true;
emit TinyFrogBoiled(tokenId);
emit TinyFrogDied(tokenId);
}
function _startTokenId() override internal pure virtual returns (uint256) {
return 1;
}
function _mintFrog(address to, uint256 numToMint) verifySupply(numToMint) private {
uint256 startTokenId = _startTokenId() + _totalMinted();
for(uint256 tokenId = startTokenId; tokenId < startTokenId+numToMint; tokenId++) {
_saveNewRandomSeed(tokenId);
}
_safeMint(to, numToMint);
}
function reserveFrog(address to, uint256 numToMint) external onlyOwner {
_mintFrog(to, numToMint);
}
function reserveFrogMany(address[] calldata recipients, uint256 numToMint) external onlyOwner {
uint256 num = recipients.length;
require(num > 0);
for (uint256 i = 0; i < num; ++i) {
_mintFrog(recipients[i], numToMint);
}
}
function publicMintFrog(uint256 numToMint) external payable {
require(mintStatus == MintStatus.PUBLIC, "Public mint closed");
require(msg.value >= _getPrice(numToMint), "Incorrect payable" );
require(_numberMinted(msg.sender) + numToMint <= maxTokensOwnableInWallet, "Exceeds max mints");
_mintFrog(msg.sender, numToMint);
}
function tokensOfOwner(address owner) external view returns (uint256[] memory) {
unchecked {
uint256 tokenIdsIdx;
address currOwnershipAddr;
uint256 tokenIdsLength = balanceOf(owner);
uint256[] memory tokenIds = new uint256[](tokenIdsLength);
TokenOwnership memory ownership;
for (uint256 i = _startTokenId(); tokenIdsIdx != tokenIdsLength; ++i) {
ownership = _ownershipAt(i);
if (ownership.burned) {
continue;
}
if (ownership.addr != address(0)) {
currOwnershipAddr = ownership.addr;
}
if (currOwnershipAddr == owner) {
tokenIds[tokenIdsIdx++] = i;
}
}
return tokenIds;
}
}
function _getPrice(uint256 numPayable) private view returns (uint256) {
uint256 numMintedAlready = _totalMinted();
uint tierIndex = 0;
for(uint i = mintSupplyLimits.length-1; i >= 0; --i ) {
if (numMintedAlready >= mintSupplyLimits[i]) {
tierIndex = i;
break;
}
}
return numPayable * mintPricing[tierIndex];
}
function getNumMinted() external view returns (uint256) {
return _totalMinted();
}
function setPricing(uint256[] calldata supply, uint256[] calldata pricing) external onlyOwner {
require(mintSupplyLimits.length == pricing.length);
mintSupplyLimits = supply;
mintPricing = pricing;
}
function setTokenMaxPerWallet(uint256 maxTokens) external onlyOwner {
maxTokensOwnableInWallet = maxTokens;
}
function getPrice(uint256 numToMint) external view returns (uint256) {
return _getPrice(numToMint);
}
function setMaxTokenSupply(uint256 _maxTokenSupply) external onlyOwner {
MAX_TOKEN_SUPPLY = _maxTokenSupply;
}
function setMintStatus(uint256 _status) external onlyOwner {
mintStatus = MintStatus(_status);
}
function setContractRenderer(address newAddress) external onlyOwner {
contractRenderer = ITinyFrogRenderer(newAddress);
}
function setBoilEnabled(bool _enabled) external onlyOwner {
boilEnabled = _enabled;
}
function setSoulbindEnabled(bool _enabled) external onlyOwner {
soulbindEnabled = _enabled;
}
function setMorphEnabled(bool _enabled) external onlyOwner {
morphEnabled = _enabled;
}
function numberMinted(address addr) external view returns(uint256){
return _numberMinted(addr);
}
function setEnableReveal(bool _revealed) external onlyOwner {
revealed = _revealed;
emit BatchMetadataUpdate(1, _totalMinted());
}
function _morphFrog(uint256 tokenId) private {
require(!dead[tokenId], "Already dead");
require(!soulbound[tokenId], "Already soulbound");
uint256 roll = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), tokenId, msg.sender, "ribbit")));
if (roll % 3 == 0) {
soulbound[tokenId] = true;
dead[tokenId] = true;
emit TinyFrogSoulbound(tokenId);
emit TinyFrogDied(tokenId);
emit TokenLocked(tokenId, address(this));
emit Lock(address(this), tokenId);
} else {
_saveNewRandomSeed(tokenId);
emit TinyFrogMorphed(tokenId);
}
emit MetadataUpdate(tokenId);
}
function morphMany(uint256[] calldata tokenIds) external {
require(morphEnabled, "Morph disabled");
uint256 num = tokenIds.length;
for (uint256 i = 0; i < num; ++i) {
uint256 tokenId = tokenIds[i];
require(_ownershipOf(tokenId).addr == _msgSender(), "Must own");
_morphFrog(tokenId);
}
}
function morphFrog(uint256 tokenId) external {
require(morphEnabled, "Morph disabled");
require(_ownershipOf(tokenId).addr == _msgSender(), "Must own");
_morphFrog(tokenId);
}
function _beforeTokenTransfers(address from, address, uint256 startTokenId, uint256 quantity) internal view override {
if (from == address(0))
return;
for (uint256 tokenId = startTokenId; tokenId < startTokenId + quantity; ++tokenId) {
if (soulbound[tokenId]) {
revert TinyFrogIsSoulbound(tokenId);
}
}
}
function isDead(uint256 tokenId) external view verifyTokenId(tokenId) returns (bool) {
return dead[tokenId];
}
function isSoulbound(uint256 tokenId) external view verifyTokenId(tokenId) returns (bool) {
return soulbound[tokenId];
}
function soulbindMany(uint256[] calldata tokenIds) external {
require(soulbindEnabled);
uint256 num = tokenIds.length;
for (uint256 i = 0; i < num; ++i) {
uint256 tokenId = tokenIds[i];
require(_ownershipOf(tokenId).addr == _msgSender(), "Must own");
_soulbindFrog(tokenId);
}
}
function soulbindFrog(uint256 tokenId) external {
require(soulbindEnabled);
require(_ownershipOf(tokenId).addr == _msgSender(), "Must own");
_soulbindFrog(tokenId);
}
function _soulbindFrog(uint256 tokenId) private {
require(!soulbound[tokenId], "Already soulbound");
soulbound[tokenId] = true;
emit TinyFrogSoulbound(tokenId);
emit MetadataUpdate(tokenId);
}
function _tokenURI(uint256 tokenId) private view returns (string memory) {
uint256 seed = seeds[tokenId];
bool isTokenDead = dead[tokenId];
bool isTokenSoulbound = soulbound[tokenId];
string memory image = isTokenDead ? contractRenderer.getDeadSVG(seed) : contractRenderer.getSVG(seed, isTokenSoulbound);
string memory json = Base64.encode(
bytes(string(
abi.encodePacked(
'{"name": ', '"Tiny Based Frog #', Strings.toString(tokenId),'",',
'"description": "Tiny Based Frogs is a 100% fully on-chain NFT collection, featuring unfathomly based on-chain interactive mechanics.",',
'"attributes":[',
contractRenderer.getTraitsMetadata(seed, isTokenSoulbound),
_getStatsMetadata(seed),
'{"trait_type":"Alive", "value":',isTokenDead ? '"No"' : '"Yes"','},',
'{"trait_type":"Soulbound", "value":',isTokenSoulbound ? '"Yes"' : '"No"','}'
'],',
'"image": "data:image/svg+xml;base64,', Base64.encode(bytes(image)), '"}'
)
))
);
return string(abi.encodePacked('data:application/json;base64,', json));
}
function _tokenUnrevealedURI(uint256 tokenId) private view returns (string memory) {
uint256 seed = seeds[tokenId];
string memory image = contractRenderer.getUnrevealedSVG(seed);
string memory json = Base64.encode(
bytes(string(
abi.encodePacked(
'{"name": ', '"Tiny Based Frog #', Strings.toString(tokenId),'",',
'"description": "Tiny Based Frogs is a 100% fully on-chain NFT collection, featuring unfathomly based on-chain interactive mechanics.",',
'"attributes":[{"trait_type":"Waiting to hatch", "value":"True"}],',
'"image": "data:image/svg+xml;base64,', Base64.encode(bytes(image)), '"}'
)
))
);
return string(abi.encodePacked('data:application/json;base64,', json));
}
function tokenURI(uint256 tokenId) override(ERC721A) public view verifyTokenId(tokenId) returns (string memory) {
if (revealed)
return _tokenURI(tokenId);
else
return _tokenUnrevealedURI(tokenId);
}
function _randStat(uint256 seed, uint256 div, uint256 min, uint256 max) private pure returns (uint256) {
return min + (seed/div) % (max-min);
}
function _getStatsMetadata(uint256 seed) private pure returns (string memory) {
string memory metadata = string(abi.encodePacked(
'{"trait_type":"Hop Power", "display_type": "number", "value":', Strings.toString(_randStat(seed, 2, 1, 5)), '},',
'{"trait_type":"Stamina", "display_type": "number", "value":', Strings.toString(_randStat(seed, 3, 1, 10)), '},',
'{"trait_type":"Lily Pad Balance", "display_type": "number", "value":', Strings.toString(_randStat(seed, 4, 1, 10)), '},',
'{"trait_type":"Swim Speed", "display_type": "number", "value":', Strings.toString(_randStat(seed, 5, 1, 10)), '},'
));
return metadata;
}
function withdraw(address to) public onlyOwner {
uint256 contractBalance = address(this).balance;
(bool success,) = payable(to).call{ value: contractBalance }("");
require(success, "WITHDRAWAL_FAILED");
}
}
文件 10 的 12:TinyFrogData.sol
pragma solidity ^0.8.0;
contract TinyFrogData {
string[] public fullPalettes = ['ff00ff', '000000', 'ffffff', 'bcbcbc', '7c7c7c', 'f8b800', 'f0d0b0', '6844fc', 'fcfcfc', 'f83800', 'f8b8f8', 'f7eecb', '004058', 'fce0a8', '940084', '00a800', 'e40058', 'f8d878', '58d854', 'ac7c00', 'd8f878', 'fca044', '503000', '00b800', '006800', 'b8f8b8'];
bytes[] public accesories = [
bytes(hex'ff00'),
bytes(hex'ff000e0003010300030116000101030001010100010103000101'),
bytes(hex'ff000c00020108000201130001010106010108000101010601011200010101050101080001010105010112000101020601010600010102060101120001010105010108000101010501011300020108000201'),
bytes(hex'ef0005051a000105050001051a000505'),
bytes(hex'500003011c000101030801011a000101020802000108010119000101010803000108010119000201030802011a0005011b000101030501011c000301'),
bytes(hex'ee0001010500010119000201030002011a00020101000201'),
bytes(hex'ee0005011a000101050701011800010107070101170001010607050114000d01'),
bytes(hex'ef0005011a000101050701011800010107070101140005010607010113000d01'),
bytes(hex'cd0007011800010101040101050901011600010101040201050901011500010101040201060901011500010101040201060401011600010101000801'),
bytes(hex'ad00060118000a01150003010108080113000e0112000e0112000e01120005010300010102000301130003010800010115000201'),
bytes(hex'ae00030101000201190001010308010102080101170001010408010102080101170001010208010a01010108010a0101180001010208010a01010108010a0101180001010208010a01010108010a01011800010101080200010101080101190001011f000101'),
bytes(hex'700003011c0001010108020401011b000101030401011c000101010401011d000101010401011a00040101040401160001010904010115000b011a000108'),
bytes(hex'ec000108010001081e00010105000108010001081e00010142000108010001081e000101'),
bytes(hex'eb0003011d000101020b010118000501030b010117000101030b0101010b0101020b010116000101040b0101010b19000101020b0101020b1b000101020b0101010b1c000101020b1e000101'),
bytes(hex'd000040b1a00020b0400020b1700010b0400010b0300010b1500010b0200020b0600010b1400010b0200020b0600010b1300010b0c00010b1200010b0c00010b1200010b0c00010b1200010b0c00010b1300010b0a00010b1400010b0a00010b1500010b0800010b1700020b0400020b1a00040b'),
bytes(hex'ce00060119000101060c010118000101060c010117000201060d0201150001010a0c010114000c01'),
bytes(hex'8d0006011900010106090101160002010209010105090101140001010208010903010309020114000101020802010609010115000c01150001010a08010115000a01'),
bytes(hex'500002011d000101010e01011d000101010e010501011c000101020e01011b0001010105030e01011a000101030e010501011a000101040e010117000c0114000101010e0105030e0105020e0105010e010115000a01'),
bytes(hex'b00002011d000101020501011b000101040f01011a0001010405010117000c01140001010105010901050109010501090105010901050109010115000a01'),
bytes(hex'ab0002011e00010101100101010004011800010102100101040501011700020101100105040101050301130001010205010101050101020b0101010501010205010113000101020506100105020115000a01'),
bytes(hex'cf0004011b000101040b01011900080117000101080b010117000101060b010118000801'),
bytes(hex'500001011d0005011a000101050801011a0005011d0001011d0005011a000101011103090107010118000101021103090207010117000101021103090107050114000d01'),
bytes(hex'8e0006011a000101040c01011a000101040c01011a000101040c01011a000101040c010117000301060d0301140001010a0c010115000a01'),
bytes(hex'8d0001010600010117000101010b010104000101010b010115000101020b010104000101020b010114000101020b0601020b010114000101010b01010304020301040101010b0101150001010204010b0104020302040101160001010404020302040101160001010803010116000a01'),
bytes(hex'b20002011d000101020501011b000201020502011800020101050101010b01100101010502011400030102050101021001010205010114000101021301010605010115000a01'),
bytes(hex'8d0008011800010106120101180001010612010119000101021203011a000101011201010305010116000401010b010101050101010503011400010104120101030501010112010115000a01'),
bytes(hex'ee0006011900010106040101180008011700010108040101160001010804010116000a01'),
bytes(hex'700002011d000101020b01011d0002011d0001010108011001011c000101021001011b0001010210020801011a0001010308011001011900010102080410010118000101010803100208010119000701'),
bytes(hex'ce00020102000201190001010213020102130101180001010613010117000201061302011500010101130101060b010101130101140001010a13010115000a01'),
bytes(hex'500004011b000101040801011900010106080101180001010108010102080101010801011800010101080101020801010108010119000101040801011a00010101080201010801011b00010102000101'),
bytes(hex'6f000201010002011a0001010210010102100101180001010110010b05100101170001010710010118000101051001011a000101031001011c000101011001011e000101'),
bytes(hex'510001141f0001141b000114020001141c000114020001141d00011402000114170001140400011403000114160001140300011404000114170001140300011402000114190001141f0001141e0001141f000114')
];
string[] public accesories_traits = [
'Default',
'Eye Brows',
'Horns',
'Hallow',
'Light Bulb',
'Angry Eye Brows',
'Baseball Cap',
'Backwards Baseball Cap',
'Fez',
'Afro',
'Bunny Ears',
'Thumb Tack',
'Flys',
'Wings',
'Bubble',
'Fedora',
'Santa Hat',
'Wizard Hat',
'Sombrero',
'Pirate Hat',
'Sailor Hat',
'Propeller Head',
'Top Hat',
'Viking Helm',
'Crown',
'Leprechaun Hat',
'Beanie',
'Party Hat',
'Cowboy Hat',
'Skull',
'Heart',
'Stink Lines'
];
bytes[] public base = [
bytes(hex'ff006f0003010100020119000101030401010204010118000101030401010204010117000201010b0101010b0104010b0101010b0101150001010104010108040101130001010504070112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010118000101030401010204010117000201010b0101010b0104010b0101010b01011500010101040201071001011300010103040101011007011200010104040101061001011300010102040101020406011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030b0101020b010118000101010b0101010b0101010b020117000201030b0104030b0101150001010104010108040101130001010504070112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010118000101030b0101020b010117000201010b0101010b0104010b0101010b01011500010101040101080401011300010104040801120001010504010301010410010113000101020401010204020304011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010118000101010b0101010b0101010b0201170002010704010115000101010401010804010113000101080404011200010106040503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f000301010002011900010103040101020401011800080117000201010b0101010b0104010b0101010b010115000101010401010804010113000101040408011200010105040603010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010115000601010802010108010115000101010003010108020101080301150001010104010108040101130001010504070112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010118000101030401010204010117000201010b0101010b0104010b0101010b010115000101010401010804010113000101050402030201020301011200010105040603010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0002010300020118000101020403010204010117000101010b020401010204010b010116000201010b0101010b0104010b0101010b0101150001010104010108040101130001010504070112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020116000b011500010102000201010b0301010b01011700050101040401150001010104010108040101130001010504070112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010118000101030401010204010117000201010b0101010b0104010b0101010b01011500010101040101080401011300010103040101030b02010204010112000101050403010303010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f00030101000201190001010304010102040101180001010104010b010401010104010b010117000201010401010304010101040101150001010104010108040101130001010404080112000101040402010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f000301010002011900010103040101020401011800010103040101020401011700050101040401150001010104010108040101130001010504070112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030b0101020b010118000101030b0101020b010117000201010b0101010b0104010b0101010b010115000101010401010804010113000101040402010504010112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030b0101020b010118000201020b0101020b010117000201030b0104010b0101010b0101150001010104010108040101130001010504070112000101050403010303010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010118000101010b0101010b0101010b020117000201070401011500010101040101010401010604010113000101050407011200010106040503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010118000101030401010204010117000201010b0101010b0104010b0101010b01011500010101040101080406010e0001010504070101150208011001010d00010105040101050307010d000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010118000101030401010204010117000201010b0101010b0104010b0101010b01011500010101040101030b0104030b01040101130001010504070112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100030118000101010b0101010b0101010b0101010b010117000101010b0101010b0101010b0101010b010116000201010b0101010b0104010b0101010b0101150001010104010108040101130001010504070112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f000301010002011900010103040101020401011800010103040101010b020117000201010b0101010b0404010115000101010401010804010113000101030402010204050112000101060402010303010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f00030101000201190001010304010102040101180001010104010b010401010104010b0101170002010104010b0304010b01040101150001010104010108040101130001010504070112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010118000101010b020401010204010117000201010b0101010b0104010b0101010b0101150001010104010108040101130001010504070112000101060401010403010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f00030101000201190001010304010102040101180001010204010b0101010b0104010117000201010b0101010b0104010b0101010b0101150001010104010108040101130001010404080112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010118000101030401010204010117000201010b0101010b0104010b0101010b01011500010101040101080401011300010105040101010b0101010b030112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f0003010100020119000101030401010204010118000101030401010204010117000201010b0101010b0104010b0101010b01011500010101040101080401011300010105040701120001010604010301010310010113000101020401010204030303011400020102040101030401010204020112000f01'),
bytes(hex'ff006f000601190001010204030b01040101180001010204010b0101010b01040101170002010204030b02040101150001010104010108040101130001010504070112000101050401010503010113000101020401010204030303011400020102040101030401010204020112000f01')
];
string[] public base_traits = [
'Default',
'Pepe',
'Shoked',
'Nana Nana Boo Boo',
'Sus',
'Unamused',
'Sunglasses',
'Model',
'Angry',
'Glasses',
'Charming',
'Beady eyes',
'Sleeping',
'Nervous',
'Drunk',
'Smug',
'Smoker',
'Sleepy',
'Alert',
'Waisted',
'Blind',
'Grumpy',
'Sad',
'Trailer Park',
'Tongue',
'Cylclops'
];
bytes[] public platform = [
bytes(hex'ff00ff00a90011010e0001010208040501010108030301010405010801010d0001010108050501010303010801010305020801010d0013010c00010101080f05030801010b001501'),
bytes(hex'ff00ff00a90011010e00010102130e16011301010d00010101130e16021301010d0013010c00010101130f16031301010b001501'),
bytes(hex'ff00ff00a70015010a0001010217011801010417010102170118010104170101031701010900010101170118020104180101011801170118010104180201011801170101090001010118090101180901011801010900030107180301071803010a001501'),
bytes(hex'ff00ff00a90011010e0001010208070403030404010801010d0001010108070403030404020801010d0013010c0001010108060403030604030801010b001501'),
bytes(hex'ff00ff00a90011010e000101010302040203010c02040203010c02040103010c0104010301010d0001010104010c0203010c0104040c02040103020c0104010301010d0013010c000101010301040103020c01040103010c02040103020c02040103010c0104010301010b001501'),
bytes(hex'ff00ff00a90011010e00010102040e0c010401010d00010101040e0c020401010d0013010c00010101040f0c030401010b001501')
];
string[] public platform_traits = [
'1',
'2',
'3',
'4',
'5',
'6'
];
bytes[] public warts = [
bytes(hex'ff00'),
bytes(hex'ff00ff000f0001031c00010322000103'),
bytes(hex'ff00ff000e0001033d000103'),
bytes(hex'ff00ed0001033d00010302000103'),
bytes(hex'ff00ff000d00010321000103'),
bytes(hex'ff00ac0001011e00010101031c0002011d00010102031d0001010103020001031c000101'),
bytes(hex'ff00ac0002011d0001010103410001031d000103'),
bytes(hex'ff00ca0002011d00010102031d0001010103020001033d000103'),
bytes(hex'ff00ed0001033d00010322000103'),
bytes(hex'ff00ff000f0001031d000103'),
bytes(hex'ff00ed0001033d000103'),
bytes(hex'ff00cb0001011e000101010321000103'),
bytes(hex'ff00ff002e0001031d000103'),
bytes(hex'ff00ed0001033d0001030100010320000103'),
bytes(hex'ff00ac0001011e00010101033c0001011e0001010103020001031c000101'),
bytes(hex'ff00ff000e0002031c000103010002031c000103')
];
string[] public warts_traits = [
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12',
'13',
'14',
'15',
'16'
];
bytes[] public misc = [
bytes(hex'4c00080118000801140004010819040110000401081904010e000201021904080a1902010c000201021904080a1902010a000201021908080a19020108000201021908080a19020108000201021908080a19020108000201021908080a190201060002010619040802190601061902010400020106190408021906010619020104000201021904080419020102190601041902010400020102190408041902010219060104190201040002010219040804190a0104190201040002010219040804190a0104190201040002010a190a0104190201040002010a190a0104190201060002010a19060104190201080002010a19060104190201080002011419020108000201141902010a000201101902010c000201101902010e0004010819040110000401081904011400080118000801'),
bytes(hex'ff006f000301010002011900010103080101020801011800010103080101020801011700020101080101030801010108010115000101010b010108080101130001010208010b010101080101010801010108030112000101010b0108030b0101010b0101010b0101010b010113000101020b0101010b0108030b03011400020102080101030801010208020112000f01')
];
}
文件 11 的 12:TinyFrogRenderer.sol
pragma solidity ^0.8.0;
import 'base64-sol/base64.sol';
import "./ITinyFrogRenderer.sol";
import "./TinyFrogData.sol";
contract TinyFrogRenderer is ITinyFrogRenderer, TinyFrogData {
struct CharacterData {
uint background;
uint palette;
uint base;
uint warts;
uint accesories;
uint platform;
}
string[] public bgPaletteColors = [
'0058F8',
'A4E4FC',
'D8B8F8',
'F8A4C0',
'FCE0A8',
'B8F8B8',
'00FCFC',
'D8D8D8',
'B8B8F8',
'BCBCBC',
'4428BC',
'940084',
'503000',
'004058',
'A80020',
'A80020'
];
string[] public baseColorLight = [
'B8F8B8',
'D8B8F8',
'A4E4FC',
'B8B8F8',
'F8B8F8',
'F0D0B0',
'FCE0A8',
'F8D878',
'D8F878',
'B8F8D8'
];
string[] public baseColorDark = [
'008888',
'00A800',
'00B800',
'AC7C00',
'E45C10',
'F83800',
'E40058',
'D800CC',
'6844FC',
'0078F8'
];
function getSVG(uint256 seed, bool showBasedPlatform) external view override returns (string memory) {
return _getSVG(seed, showBasedPlatform);
}
function _getSVG(uint256 seed, bool showBasedPlatform) internal view returns (string memory) {
CharacterData memory data = _generateCharacterData(seed);
string memory colorLight = baseColorLight[data.palette];
string memory colorDark = baseColorDark[data.palette];
string memory image = string(abi.encodePacked(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" shape-rendering="crispEdges" width="512" height="512">'
'<rect width="100%" height="100%" fill="#', bgPaletteColors[data.background], '"/>',
_renderRectsBaseColorSwap(base[data.base], fullPalettes, colorLight, colorDark),
_renderRectsBaseColorSwap(warts[data.warts], fullPalettes, colorLight, colorDark),
_renderRects(accesories[data.accesories], fullPalettes),
showBasedPlatform ? _renderRects(platform[data.platform], fullPalettes) : "",
'</svg>'
));
return image;
}
function getUnrevealedSVG(uint256 seed) external view override returns (string memory) {
return _getUnrevealedSVG(seed);
}
function _getUnrevealedSVG(uint256 seed) internal view returns (string memory) {
CharacterData memory data = _generateCharacterData(seed);
string memory image = string(abi.encodePacked(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" shape-rendering="crispEdges" width="512" height="512">'
'<rect width="100%" height="100%" fill="#', bgPaletteColors[data.background], '"/>',
_renderRects(misc[0], fullPalettes),
'</svg>'
));
return image;
}
function getDeadSVG(uint256 seed) external view override returns (string memory) {
return _getDeadSVG(seed);
}
function _getDeadSVG(uint256) internal view returns (string memory) {
string memory image = string(abi.encodePacked(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" shape-rendering="crispEdges" width="512" height="512">'
'<rect width="100%" height="100%" fill="#000000"/>',
_renderRects(misc[1], fullPalettes),
'</svg>'
));
return image;
}
function getTraitsMetadata(uint256 seed, bool showBasedPlatform) external override view returns (string memory) {
return _getTraitsMetadata(seed, showBasedPlatform);
}
function _getTraitsMetadata(uint256 seed, bool showBasedPlatform) internal view returns (string memory) {
CharacterData memory data = _generateCharacterData(seed);
string[17] memory lookup = [
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '10', '11', '12', '13', '14',
'15', '16'
];
string memory metadata = string(abi.encodePacked(
'{"trait_type":"Background", "value":"', lookup[data.background+1], '"},',
'{"trait_type":"Palette", "value":"', lookup[data.palette+1], '"},',
'{"trait_type":"Body", "value":"', base_traits[data.base], '"},',
'{"trait_type":"Warts", "value":"', warts_traits[data.warts], '"},',
'{"trait_type":"Accessories", "value":"', accesories_traits[data.accesories], '"},'
'{"trait_type":"Platform", "value":"', showBasedPlatform ? "None":platform_traits[data.platform], '"},'
));
return metadata;
}
function _renderRects(bytes memory data, string[] memory palette) private pure returns (string memory) {
string[33] memory lookup = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'10', '11', '12', '13', '14', '15', '16', '17', '18', '19',
'20', '21', '22', '23', '24', '25', '26', '27', '28', '29',
'30', '31', '32'
];
string memory rects;
uint256 drawIndex = 0;
for (uint256 i = 0; i < data.length; i = i+2) {
uint8 runLength = uint8(data[i]);
uint8 colorIndex = uint8(data[i+1]);
if (colorIndex != 0) {
uint8 x = uint8(drawIndex % 32);
uint8 y = uint8(drawIndex / 32);
string memory color = palette[colorIndex];
rects = string(abi.encodePacked(rects, '<rect width="', lookup[runLength], '" height="1" x="', lookup[x], '" y="', lookup[y], '" fill="#', color, '"/>'));
}
drawIndex += runLength;
}
return rects;
}
function _renderRectsBaseColorSwap(bytes memory data, string[] memory palette, string memory colorLight, string memory colorDark) private pure returns (string memory) {
string[33] memory lookup = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'10', '11', '12', '13', '14', '15', '16', '17', '18', '19',
'20', '21', '22', '23', '24', '25', '26', '27', '28', '29',
'30', '31', '32'
];
string memory rects;
uint256 drawIndex = 0;
for (uint256 i = 0; i < data.length; i = i+2) {
uint8 runLength = uint8(data[i]);
uint8 colorIndex = uint8(data[i+1]);
uint8 x = uint8(drawIndex % 32);
uint8 y = uint8(drawIndex / 32);
if (colorIndex == 0) {
}
else if (colorIndex==3) {
rects = string(abi.encodePacked(rects, '<rect width="', lookup[runLength], '" height="1" x="', lookup[x], '" y="', lookup[y], '" fill="#', colorLight, '"/>'));
}
else if (colorIndex==4) {
rects = string(abi.encodePacked(rects, '<rect width="', lookup[runLength], '" height="1" x="', lookup[x], '" y="', lookup[y], '" fill="#', colorDark, '"/>'));
}
else {
rects = string(abi.encodePacked(rects, '<rect width="', lookup[runLength], '" height="1" x="', lookup[x], '" y="', lookup[y], '" fill="#', palette[colorIndex], '"/>'));
}
drawIndex += runLength;
}
return rects;
}
function _generateCharacterData(uint256 seed) private view returns (CharacterData memory) {
return CharacterData({
background: seed % bgPaletteColors.length,
palette: (seed/2) % baseColorLight.length,
base: (seed/3) % base.length,
warts: (seed/4) % warts.length,
accesories: (seed/5) % accesories.length,
platform: (seed/6) % platform.length
});
}
}
文件 12 的 12:base64.sol
pragma solidity >=0.6.0;
library Base64 {
string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
bytes internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000"
hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000"
hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000"
hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000";
function encode(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return '';
string memory table = TABLE_ENCODE;
uint256 encodedLen = 4 * ((data.length + 2) / 3);
string memory result = new string(encodedLen + 32);
assembly {
mstore(result, encodedLen)
let tablePtr := add(table, 1)
let dataPtr := data
let endPtr := add(dataPtr, mload(data))
let resultPtr := add(result, 32)
for {} lt(dataPtr, endPtr) {}
{
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and( input, 0x3F))))
resultPtr := add(resultPtr, 1)
}
switch mod(mload(data), 3)
case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
}
return result;
}
function decode(string memory _data) internal pure returns (bytes memory) {
bytes memory data = bytes(_data);
if (data.length == 0) return new bytes(0);
require(data.length % 4 == 0, "invalid base64 decoder input");
bytes memory table = TABLE_DECODE;
uint256 decodedLen = (data.length / 4) * 3;
bytes memory result = new bytes(decodedLen + 32);
assembly {
let lastBytes := mload(add(data, mload(data)))
if eq(and(lastBytes, 0xFF), 0x3d) {
decodedLen := sub(decodedLen, 1)
if eq(and(lastBytes, 0xFFFF), 0x3d3d) {
decodedLen := sub(decodedLen, 1)
}
}
mstore(result, decodedLen)
let tablePtr := add(table, 1)
let dataPtr := data
let endPtr := add(dataPtr, mload(data))
let resultPtr := add(result, 32)
for {} lt(dataPtr, endPtr) {}
{
dataPtr := add(dataPtr, 4)
let input := mload(dataPtr)
let output := add(
add(
shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)),
shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))),
add(
shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)),
and(mload(add(tablePtr, and( input , 0xFF))), 0xFF)
)
)
mstore(resultPtr, shl(232, output))
resultPtr := add(resultPtr, 3)
}
}
return result;
}
}
{
"compilationTarget": {
"contracts/TinyFrog.sol": "TinyFrog"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"details": {
"constantOptimizer": true,
"cse": true,
"deduplicate": true,
"inliner": true,
"jumpdestRemover": true,
"orderLiterals": true,
"peephole": true,
"yul": false
},
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TinyFrogIsSoulbound","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"unlocker","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Lock","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","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":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TinyFrogBoiled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TinyFrogDied","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TinyFrogMorphed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TinyFrogSoulbound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"approvedContract","type":"address"}],"name":"TokenLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"MAX_TOKEN_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"accesories","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"accesories_traits","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","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":"","type":"uint256"}],"name":"base","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"baseColorDark","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"baseColorLight","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"base_traits","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"bgPaletteColors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"boilEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"boilFrog","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractRenderer","outputs":[{"internalType":"contract ITinyFrogRenderer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"dead","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"fullPalettes","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"seed","type":"uint256"}],"name":"getDeadSVG","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numToMint","type":"uint256"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"bool","name":"showBasedPlatform","type":"bool"}],"name":"getSVG","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"bool","name":"showBasedPlatform","type":"bool"}],"name":"getTraitsMetadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"seed","type":"uint256"}],"name":"getUnrevealedSVG","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"tokenId","type":"uint256"}],"name":"isDead","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isSoulbound","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTokensOwnableInWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintPricing","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintStatus","outputs":[{"internalType":"enum TinyFrog.MintStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintSupplyLimits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"misc","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"morphEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"morphFrog","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"morphMany","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"numberMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"platform","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"platform_traits","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numToMint","type":"uint256"}],"name":"publicMintFrog","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"numToMint","type":"uint256"}],"name":"reserveFrog","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256","name":"numToMint","type":"uint256"}],"name":"reserveFrogMany","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revealed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"seeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setBoilEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"setContractRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_revealed","type":"bool"}],"name":"setEnableReveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTokenSupply","type":"uint256"}],"name":"setMaxTokenSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_status","type":"uint256"}],"name":"setMintStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setMorphEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"supply","type":"uint256[]"},{"internalType":"uint256[]","name":"pricing","type":"uint256[]"}],"name":"setPricing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setSoulbindEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxTokens","type":"uint256"}],"name":"setTokenMaxPerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"soulbindEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"soulbindFrog","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"soulbindMany","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"soulbound","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"warts","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"warts_traits","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]