文件 1 的 30:AccessControl.sol
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view override returns (bool) {
return _roles[role].members[account];
}
function _checkRole(bytes32 role, address account) internal view {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) private {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) private {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 30:Address.sol
pragma solidity ^0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 3 的 30: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;
}
}
文件 4 的 30:Counters.sol
pragma solidity ^0.8.0;
library Counters {
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}
文件 5 的 30:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 6 的 30:ERC721.sol
pragma solidity ^0.8.0;
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
using Address for address;
using Strings for uint256;
string private _name;
string private _symbol;
mapping(uint256 => address) private _owners;
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
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) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
function _baseURI() internal view virtual returns (string memory) {
return "";
}
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721.ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
function getApproved(uint256 tokenId) public view virtual override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public virtual override {
require(operator != _msgSender(), "ERC721: approve to caller");
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
function _safeMint(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, _data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
}
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
_approve(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
}
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}
文件 7 的 30:ERC721Enumerable.sol
pragma solidity ^0.8.0;
import "../ERC721.sol";
import "./IERC721Enumerable.sol";
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
mapping(uint256 => uint256) private _ownedTokensIndex;
uint256[] private _allTokens;
mapping(uint256 => uint256) private _allTokensIndex;
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
return _ownedTokens[owner][index];
}
function totalSupply() public view virtual override returns (uint256) {
return _allTokens.length;
}
function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
return _allTokens[index];
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override {
super._beforeTokenTransfer(from, to, tokenId);
if (from == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (from != to) {
_removeTokenFromOwnerEnumeration(from, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (to != from) {
_addTokenToOwnerEnumeration(to, tokenId);
}
}
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = ERC721.balanceOf(to);
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
uint256 tokenIndex = _ownedTokensIndex[tokenId];
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId;
_ownedTokensIndex[lastTokenId] = tokenIndex;
}
delete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId];
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId;
_allTokensIndex[lastTokenId] = tokenIndex;
delete _allTokensIndex[tokenId];
_allTokens.pop();
}
}
文件 8 的 30:IAccessControl.sol
pragma solidity ^0.8.0;
interface IAccessControl {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 9 的 30:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 10 的 30:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
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
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
}
文件 11 的 30:IERC721Enumerable.sol
pragma solidity ^0.8.0;
import "../IERC721.sol";
interface IERC721Enumerable is IERC721 {
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
function tokenByIndex(uint256 index) external view returns (uint256);
}
文件 12 的 30:IERC721Metadata.sol
pragma solidity ^0.8.0;
import "../IERC721.sol";
interface IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
文件 13 的 30:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 14 的 30:IKarmaScore.sol
pragma solidity >=0.8.4;
interface IKarmaScore {
function verify(
address account,
uint256 score,
bytes calldata data
) external view returns (bool);
function merkleRoot() external view returns (bytes32);
function setMerkleRoot(bytes32 _merkleRoot) external;
}
文件 15 的 30:IN.sol
pragma solidity 0.8.6;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
interface IN is IERC721Enumerable, IERC721Metadata {
function getFirst(uint256 tokenId) external view returns (uint256);
function getSecond(uint256 tokenId) external view returns (uint256);
function getThird(uint256 tokenId) external view returns (uint256);
function getFourth(uint256 tokenId) external view returns (uint256);
function getFifth(uint256 tokenId) external view returns (uint256);
function getSixth(uint256 tokenId) external view returns (uint256);
function getSeventh(uint256 tokenId) external view returns (uint256);
function getEight(uint256 tokenId) external view returns (uint256);
}
文件 16 的 30:INOwnerResolver.sol
pragma solidity 0.8.6;
interface INOwnerResolver {
function ownerOf(uint256 nid) external view returns (address);
function balanceOf(address account) external view returns (uint256);
function nOwned(address owner) external view returns (uint256[] memory);
}
文件 17 的 30:INilPass.sol
pragma solidity >=0.8.4;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
interface INilPass is IERC721Enumerable {
struct MintParams {
uint256 reservedAllowance;
uint256 maxTotalSupply;
uint256 nHoldersMintsAvailable;
uint256 openMintsAvailable;
uint256 totalMintsAvailable;
uint256 nHolderPriceInWei;
uint256 openPriceInWei;
uint256 totalSupply;
uint256 maxMintAllowance;
bool onlyNHolders;
bool supportsTokenId;
}
function mint(
address recipient,
uint8 amount,
uint256 paid,
bytes calldata data
) external;
function mintTokenId(
address recipient,
uint256[] calldata tokenIds,
uint256 paid,
bytes calldata data
) external;
function mintWithN(
address recipient,
uint256[] calldata tokenIds,
uint256 paid,
bytes calldata data
) external;
function totalMintsAvailable() external view returns (uint256);
function maxTotalSupply() external view returns (uint256);
function mintParameters() external view returns (MintParams memory);
function tokenExists(uint256 tokenId) external view returns (bool);
function canMint(address account, bytes calldata data) external view returns (bool);
function nUsed(uint256 nid) external view returns (bool);
}
文件 18 的 30:IPricingStrategy.sol
pragma solidity 0.8.6;
interface IPricingStrategy {
function getNextPriceForNHoldersInWei(
uint256 numberOfMints,
address account,
bytes memory data
) external view returns (uint256);
function getNextPriceForOpenMintInWei(
uint256 numberOfMints,
address account,
bytes memory data
) external view returns (uint256);
}
文件 19 的 30:IRarible.sol
pragma solidity 0.8.6;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
interface IRarible is IERC721Enumerable, IERC721Metadata {
function balanceOf(address _owner, uint256 _id) external view returns (uint256);
}
文件 20 的 30:LinkTokenInterface.sol
pragma solidity ^0.8.0;
interface LinkTokenInterface {
function allowance(
address owner,
address spender
)
external
view
returns (
uint256 remaining
);
function approve(
address spender,
uint256 value
)
external
returns (
bool success
);
function balanceOf(
address owner
)
external
view
returns (
uint256 balance
);
function decimals()
external
view
returns (
uint8 decimalPlaces
);
function decreaseApproval(
address spender,
uint256 addedValue
)
external
returns (
bool success
);
function increaseApproval(
address spender,
uint256 subtractedValue
) external;
function name()
external
view
returns (
string memory tokenName
);
function symbol()
external
view
returns (
string memory tokenSymbol
);
function totalSupply()
external
view
returns (
uint256 totalTokensIssued
);
function transfer(
address to,
uint256 value
)
external
returns (
bool success
);
function transferAndCall(
address to,
uint256 value,
bytes calldata data
)
external
returns (
bool success
);
function transferFrom(
address from,
address to,
uint256 value
)
external
returns (
bool success
);
}
文件 21 的 30:Math.sol
pragma solidity ^0.8.0;
library Math {
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 / b + (a % b == 0 ? 0 : 1);
}
}
文件 22 的 30:NilPassCore.sol
pragma solidity 0.8.6;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "../interfaces/IN.sol";
import "../interfaces/INilPass.sol";
import "../interfaces/IPricingStrategy.sol";
abstract contract NilPassCore is ERC721Enumerable, ReentrancyGuard, AccessControl, INilPass, IPricingStrategy {
uint128 public constant MAX_MULTI_MINT_AMOUNT = 32;
uint128 public constant MAX_N_TOKEN_ID = 8888;
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN");
bytes32 public constant DAO_ROLE = keccak256("DAO");
IN public immutable n;
uint16 public reserveMinted;
uint256 public mintedOutsideNRange;
address public masterMint;
DerivativeParameters public derivativeParams;
uint128 maxTokenId;
struct DerivativeParameters {
bool onlyNHolders;
bool supportsTokenId;
uint16 reservedAllowance;
uint128 maxTotalSupply;
uint128 maxMintAllowance;
}
event Minted(address to, uint256 tokenId);
constructor(
string memory name,
string memory symbol,
IN n_,
DerivativeParameters memory derivativeParams_,
address masterMint_,
address dao_
) ERC721(name, symbol) {
derivativeParams = derivativeParams_;
require(derivativeParams.maxTotalSupply > 0, "NilPass:INVALID_SUPPLY");
require(
!derivativeParams.onlyNHolders ||
(derivativeParams.onlyNHolders && derivativeParams.maxTotalSupply <= MAX_N_TOKEN_ID),
"NilPass:INVALID_SUPPLY"
);
require(derivativeParams.maxTotalSupply >= derivativeParams.reservedAllowance, "NilPass:INVALID_ALLOWANCE");
require(masterMint_ != address(0), "NilPass:INVALID_MASTERMINT");
require(dao_ != address(0), "NilPass:INVALID_DAO");
n = n_;
masterMint = masterMint_;
derivativeParams.maxMintAllowance = derivativeParams.maxMintAllowance < MAX_MULTI_MINT_AMOUNT
? derivativeParams.maxMintAllowance
: MAX_MULTI_MINT_AMOUNT;
maxTokenId = derivativeParams.maxTotalSupply > MAX_N_TOKEN_ID
? derivativeParams.maxTotalSupply
: MAX_N_TOKEN_ID;
_setupRole(ADMIN_ROLE, msg.sender);
_setupRole(DAO_ROLE, dao_);
_setRoleAdmin(ADMIN_ROLE, ADMIN_ROLE);
_setRoleAdmin(DAO_ROLE, DAO_ROLE);
}
modifier onlyAdmin() {
require(hasRole(ADMIN_ROLE, msg.sender), "Nil:ACCESS_DENIED");
_;
}
modifier onlyDAO() {
require(hasRole(DAO_ROLE, msg.sender), "Nil:ACCESS_DENIED");
_;
}
function mint(
address,
uint8,
uint256,
bytes calldata
) public virtual override nonReentrant {
require(false, "MINTING DISABLED");
}
function mintTokenId(
address,
uint256[] calldata,
uint256,
bytes calldata
) public virtual override nonReentrant {
require(false, "MINTING DISABLED");
}
function mintWithN(
address,
uint256[] calldata,
uint256,
bytes calldata
) public virtual override nonReentrant {
require(false, "MINTING DISABLED");
}
function _safeMint(address to, uint256 tokenId) internal virtual override {
require(msg.sender == masterMint, "NilPass:INVALID_MINTER");
super._safeMint(to, tokenId);
emit Minted(to, tokenId);
}
function setOnlyNHolders(bool status) public onlyAdmin {
derivativeParams.onlyNHolders = status;
}
function nHoldersMintsAvailable() public view returns (uint256) {
return derivativeParams.reservedAllowance - reserveMinted;
}
function openMintsAvailable() public view returns (uint256) {
uint256 maxOpenMints = derivativeParams.maxTotalSupply - derivativeParams.reservedAllowance;
uint256 currentOpenMints = totalSupply() - reserveMinted;
return maxOpenMints - currentOpenMints;
}
function totalMintsAvailable() public view virtual override returns (uint256) {
return nHoldersMintsAvailable() + openMintsAvailable();
}
function mintParameters() external view override returns (INilPass.MintParams memory) {
return
INilPass.MintParams({
reservedAllowance: derivativeParams.reservedAllowance,
maxTotalSupply: derivativeParams.maxTotalSupply,
openMintsAvailable: openMintsAvailable(),
totalMintsAvailable: totalMintsAvailable(),
nHoldersMintsAvailable: nHoldersMintsAvailable(),
nHolderPriceInWei: getNextPriceForNHoldersInWei(1, address(0x1), ""),
openPriceInWei: getNextPriceForOpenMintInWei(1, address(0x1), ""),
totalSupply: totalSupply(),
onlyNHolders: derivativeParams.onlyNHolders,
maxMintAllowance: derivativeParams.maxMintAllowance,
supportsTokenId: derivativeParams.supportsTokenId
});
}
function tokenExists(uint256 tokenId) external view override returns (bool) {
return _exists(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC721Enumerable, IERC165, AccessControl)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
function maxTotalSupply() external view override returns (uint256) {
return derivativeParams.maxTotalSupply;
}
function reservedAllowance() public view returns (uint16) {
return derivativeParams.reservedAllowance;
}
function getNextPriceForNHoldersInWei(
uint256 numberOfMints,
address account,
bytes memory data
) public view virtual override returns (uint256);
function getNextPriceForOpenMintInWei(
uint256 numberOfMints,
address account,
bytes memory data
) public view virtual override returns (uint256);
function canMint(address account, bytes calldata data) external view virtual override returns (bool);
}
文件 23 的 30:NilProtocolUtils.sol
pragma solidity 0.8.6;
library NilProtocolUtils {
bytes internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function base64encode(bytes memory data) external pure returns (string memory) {
uint256 len = data.length;
if (len == 0) return "";
uint256 encodedLen = 4 * ((len + 2) / 3);
bytes memory result = new bytes(encodedLen + 32);
bytes memory table = TABLE;
assembly {
let tablePtr := add(table, 1)
let resultPtr := add(result, 32)
for {
let i := 0
} lt(i, len) {
} {
i := add(i, 3)
let input := and(mload(add(data, i)), 0xffffff)
let out := mload(add(tablePtr, and(shr(18, input), 0x3F)))
out := shl(8, out)
out := add(out, and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF))
out := shl(8, out)
out := add(out, and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF))
out := shl(8, out)
out := add(out, and(mload(add(tablePtr, and(input, 0x3F))), 0xFF))
out := shl(224, out)
mstore(resultPtr, out)
resultPtr := add(resultPtr, 4)
}
switch mod(len, 3)
case 1 {
mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
}
case 2 {
mstore(sub(resultPtr, 1), shl(248, 0x3d))
}
mstore(result, encodedLen)
}
return string(result);
}
function stringify(uint256 value) external pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
}
文件 24 的 30:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 25 的 30:SeedPhrase.sol
pragma solidity >=0.8.4;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
import "./SeedPhrasePricing.sol";
import "../interfaces/IN.sol";
import "../interfaces/IRarible.sol";
import "../interfaces/IKarmaScore.sol";
import "../interfaces/INOwnerResolver.sol";
import "../libraries/NilProtocolUtils.sol";
import "../libraries/SeedPhraseUtils.sol";
contract SeedPhrase is SeedPhrasePricing, VRFConsumerBase {
using Strings for uint256;
using Strings for uint16;
using Strings for uint8;
using Counters for Counters.Counter;
using SeedPhraseUtils for SeedPhraseUtils.Random;
Counters.Counter private _doublePanelTokens;
Counters.Counter private _tokenIds;
address private _owner;
mapping(uint256 => bool) public override nUsed;
mapping(PreSaleType => uint16) public presaleLimits;
address[] private genesisSketchAddresses;
uint16[] private bipWordIds = new uint16[](2048);
IRarible public immutable rarible;
INOwnerResolver public immutable nOwnerResolver;
IKarmaScore public immutable karma;
struct Maps {
mapping(uint256 => uint256[2]) burnedTokensPairings;
mapping(uint16 => uint16) doubleWordPairings;
mapping(uint256 => uint8) doubleTokenRarity;
mapping(address => bool) ogAddresses;
mapping(uint256 => bytes32) tokenSeed;
}
struct Config {
bool preSaleActive;
bool publicSaleActive;
bool isSaleHalted;
bool bipWordsShuffled;
bool vrfNumberGenerated;
bool isBurnActive;
bool isOwnerSupplyMinted;
bool isGsAirdropComplete;
uint8 ownerSupply;
uint16 maxPublicMint;
uint16 karmaRequirement;
uint32 preSaleLaunchTime;
uint32 publicSaleLaunchTime;
uint256 doubleBurnTokens;
uint256 linkFee;
uint256 raribleTokenId;
uint256 vrfRandomValue;
address vrfCoordinator;
address linkToken;
bytes32 vrfKeyHash;
}
struct ContractAddresses {
address n;
address masterMint;
address dao;
address nOwnersRegistry;
address vrfCoordinator;
address linkToken;
address karmaAddress;
address rarible;
}
Config private config;
Maps private maps;
event Burnt(address to, uint256 firstBurntToken, uint256 secondBurntToken, uint256 doublePaneledToken);
DerivativeParameters params = DerivativeParameters(false, false, 0, 2048, 4);
constructor(
ContractAddresses memory contractAddresses,
bytes32 _vrfKeyHash,
uint256 _linkFee
)
SeedPhrasePricing(
"Seed Phrase",
"SEED",
IN(contractAddresses.n),
params,
30000000000000000,
60000000000000000,
contractAddresses.masterMint,
contractAddresses.dao
)
VRFConsumerBase(contractAddresses.vrfCoordinator, contractAddresses.linkToken)
{
_tokenIds.increment();
presaleLimits[PreSaleType.N] = 400;
presaleLimits[PreSaleType.Karma] = 800;
presaleLimits[PreSaleType.GenesisSketch] = 40;
presaleLimits[PreSaleType.OG] = 300;
presaleLimits[PreSaleType.GM] = 300;
nOwnerResolver = INOwnerResolver(contractAddresses.nOwnersRegistry);
rarible = IRarible(contractAddresses.rarible);
karma = IKarmaScore(contractAddresses.karmaAddress);
config.maxPublicMint = 8;
config.ownerSupply = 20;
config.preSaleLaunchTime = 1639591200;
config.publicSaleLaunchTime = 1639598400;
config.raribleTokenId = 706480;
config.karmaRequirement = 1020;
config.vrfCoordinator = contractAddresses.vrfCoordinator;
config.linkToken = contractAddresses.linkToken;
config.linkFee = _linkFee;
config.vrfKeyHash = _vrfKeyHash;
_owner = 0x7F05F27CC5D83C3e879C53882de13Cc1cbCe8a8c;
}
function owner() external view virtual returns (address) {
return _owner;
}
function setOwner(address owner_) external onlyAdmin {
_owner = owner_;
}
function contractURI() public pure returns (string memory) {
return "https://www.seedphrase.codes/metadata/seedphrase-metadata.json";
}
function getVrfSeed() external onlyAdmin returns (bytes32) {
require(!config.vrfNumberGenerated, "SP:VRF_ALREADY_CALLED");
require(LINK.balanceOf(address(this)) >= config.linkFee, "SP:NOT_ENOUGH_LINK");
return requestRandomness(config.vrfKeyHash, config.linkFee);
}
function fulfillRandomness(bytes32, uint256 randomNumber) internal override {
config.vrfRandomValue = randomNumber;
config.vrfNumberGenerated = true;
}
function _getTokenSeed(uint256 tokenId) internal view returns (bytes32) {
return maps.tokenSeed[tokenId];
}
function _getBipWordIdFromTokenId(uint256 tokenId) internal view returns (uint16) {
return bipWordIds[tokenId - 1];
}
function tokenSVG(uint256 tokenId) public view virtual returns (string memory svg, bytes memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
SeedPhraseUtils.Random memory random = SeedPhraseUtils.Random({
seed: uint256(_getTokenSeed(tokenId)),
offsetBit: 0
});
uint16 bipWordId;
uint16 secondBipWordId = 0;
uint8 rarityValue = 0;
if (tokenId >= 3000) {
uint256[2] memory tokens = maps.burnedTokensPairings[tokenId];
bipWordId = _getBipWordIdFromTokenId(tokens[0]);
secondBipWordId = _getBipWordIdFromTokenId(tokens[1]);
rarityValue = maps.doubleTokenRarity[tokenId];
} else {
bipWordId = _getBipWordIdFromTokenId(tokenId);
}
(bytes memory traits, SeedPhraseUtils.Attrs memory attributes) = SeedPhraseUtils.getTraitsAndAttributes(
bipWordId,
secondBipWordId,
rarityValue,
random
);
return (SeedPhraseUtils.render(random, attributes), traits);
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
(string memory output, bytes memory traits) = tokenSVG(tokenId);
return SeedPhraseUtils.getTokenURI(output, traits, tokenId);
}
function setPreSaleState(bool _preSaleActiveState) external onlyAdmin {
config.preSaleActive = _preSaleActiveState;
}
function setPublicSaleState(bool _publicSaleActiveState) external onlyAdmin {
config.publicSaleActive = _publicSaleActiveState;
}
function setPreSaleTime(uint32 _time) external onlyAdmin {
config.preSaleLaunchTime = _time;
}
function setPublicSaleTime(uint32 _time) external onlyAdmin {
config.publicSaleLaunchTime = _time;
}
function setSaleHaltedState(bool _saleHaltedState) external onlyAdmin {
config.isSaleHalted = _saleHaltedState;
}
function setBurnActiveState(bool _burnActiveState) external onlyAdmin {
config.isBurnActive = _burnActiveState;
}
function setGenesisSketchAllowList(address[] calldata addresses) external onlyAdmin {
genesisSketchAddresses = addresses;
}
function setOgAllowList(address[] calldata addresses) external onlyAdmin {
for (uint256 i = 0; i < addresses.length; i++) {
maps.ogAddresses[addresses[i]] = true;
}
}
function _isPreSaleActive() internal view returns (bool) {
return ((block.timestamp >= config.preSaleLaunchTime || config.preSaleActive) && !config.isSaleHalted);
}
function _isPublicSaleActive() internal view override returns (bool) {
return ((block.timestamp >= config.publicSaleLaunchTime || config.publicSaleActive) && !config.isSaleHalted);
}
function _canMintPresale(
address addr,
uint256 amount,
bytes memory data
) internal view override returns (bool, PreSaleType) {
if (maps.ogAddresses[addr] && presaleLimits[PreSaleType.OG] - amount >= 0) {
return (true, PreSaleType.OG);
}
bool isGsHolder;
for (uint256 i = 0; i < genesisSketchAddresses.length; i++) {
if (genesisSketchAddresses[i] == addr) {
isGsHolder = true;
}
}
if (isGsHolder && presaleLimits[PreSaleType.GenesisSketch] - amount >= 0) {
return (true, PreSaleType.GenesisSketch);
}
if (rarible.balanceOf(addr, config.raribleTokenId) > 0 && presaleLimits[PreSaleType.GM] - amount > 0) {
return (true, PreSaleType.GM);
}
uint256 karmaScore = SeedPhraseUtils.getKarma(karma, data, addr);
if (nOwnerResolver.balanceOf(addr) > 0) {
if (karmaScore >= config.karmaRequirement && presaleLimits[PreSaleType.Karma] - amount >= 0) {
return (true, PreSaleType.Karma);
}
if (presaleLimits[PreSaleType.N] - amount >= 0) {
return (true, PreSaleType.N);
}
}
return (false, PreSaleType.None);
}
function canMint(address account, bytes calldata data) public view virtual override returns (bool) {
if (config.isBurnActive) {
return false;
}
uint256 balance = balanceOf(account);
if (_isPublicSaleActive() && (totalMintsAvailable() > 0) && balance < config.maxPublicMint) {
return true;
}
if (_isPreSaleActive()) {
(bool preSaleEligible, ) = _canMintPresale(account, 1, data);
return preSaleEligible;
}
return false;
}
function mintWithN(
address recipient,
uint256[] calldata tokenIds,
uint256 paid,
bytes calldata data
) public virtual override nonReentrant {
uint256 maxTokensToMint = tokenIds.length;
(bool preSaleEligible, PreSaleType presaleType) = _canMintPresale(recipient, maxTokensToMint, data);
require(config.bipWordsShuffled && config.vrfNumberGenerated, "SP:ENV_NOT_INIT");
require(_isPublicSaleActive() || (_isPreSaleActive() && preSaleEligible), "SP:SALE_NOT_ACTIVE");
require(
balanceOf(recipient) + maxTokensToMint <= _getMaxMintPerWallet(),
"NilPass:MINT_ABOVE_MAX_MINT_ALLOWANCE"
);
require(!config.isBurnActive, "SP:SALE_OVER");
require(totalSupply() + maxTokensToMint <= params.maxTotalSupply, "NilPass:MAX_ALLOCATION_REACHED");
uint256 price = getNextPriceForNHoldersInWei(maxTokensToMint, recipient, data);
require(paid == price, "NilPass:INVALID_PRICE");
for (uint256 i = 0; i < maxTokensToMint; i++) {
require(!nUsed[tokenIds[i]], "SP:N_ALREADY_USED");
uint256 tokenId = _tokenIds.current();
require(tokenId <= params.maxTotalSupply, "SP:TOKEN_TOO_HIGH");
maps.tokenSeed[tokenId] = SeedPhraseUtils.generateSeed(tokenId, config.vrfRandomValue);
_safeMint(recipient, tokenId);
_tokenIds.increment();
nUsed[tokenIds[i]] = true;
}
if (preSaleEligible) {
presaleLimits[presaleType] -= uint16(maxTokensToMint);
}
}
function mint(
address recipient,
uint8 amount,
uint256 paid,
bytes calldata data
) public virtual override nonReentrant {
(bool preSaleEligible, PreSaleType presaleType) = _canMintPresale(recipient, amount, data);
require(config.bipWordsShuffled && config.vrfNumberGenerated, "SP:ENV_NOT_INIT");
require(
_isPublicSaleActive() ||
(_isPreSaleActive() &&
preSaleEligible &&
(presaleType != PreSaleType.N && presaleType != PreSaleType.Karma)),
"SP:SALE_NOT_ACTIVE"
);
require(!config.isBurnActive, "SP:SALE_OVER");
require(balanceOf(recipient) + amount <= _getMaxMintPerWallet(), "NilPass:MINT_ABOVE_MAX_MINT_ALLOWANCE");
require(totalSupply() + amount <= params.maxTotalSupply, "NilPass:MAX_ALLOCATION_REACHED");
uint256 price = getNextPriceForOpenMintInWei(amount, recipient, data);
require(paid == price, "NilPass:INVALID_PRICE");
for (uint256 i = 0; i < amount; i++) {
uint256 tokenId = _tokenIds.current();
require(tokenId <= params.maxTotalSupply, "SP:TOKEN_TOO_HIGH");
maps.tokenSeed[tokenId] = SeedPhraseUtils.generateSeed(tokenId, config.vrfRandomValue);
_safeMint(recipient, tokenId);
_tokenIds.increment();
}
if (preSaleEligible) {
presaleLimits[presaleType] -= amount;
}
}
function mintOwnerSupply(address account) public nonReentrant onlyAdmin {
require(!config.isOwnerSupplyMinted, "SP:ALREADY_MINTED");
require(config.bipWordsShuffled && config.vrfNumberGenerated, "SP:ENV_NOT_INIT");
require(
totalSupply() + config.ownerSupply <= params.maxTotalSupply,
"NilPass:MAX_ALLOCATION_REACHED"
);
for (uint256 i = 0; i < config.ownerSupply; i++) {
uint256 tokenId = _tokenIds.current();
maps.tokenSeed[tokenId] = SeedPhraseUtils.generateSeed(tokenId, config.vrfRandomValue);
_mint(account, tokenId);
_tokenIds.increment();
}
config.isOwnerSupplyMinted = true;
}
function burnForDoublePanel(uint256 firstTokenId, uint256 secondTokenId) public nonReentrant {
require(config.isBurnActive, "SP:BURN_INACTIVE");
require(ownerOf(firstTokenId) == msg.sender && ownerOf(secondTokenId) == msg.sender, "SP:INCORRECT_OWNER");
require(firstTokenId != secondTokenId, "SP:EQUAL_TOKENS");
require(
isValidPairing(_getBipWordIdFromTokenId(firstTokenId), _getBipWordIdFromTokenId(secondTokenId)),
"SP:INVALID_TOKEN_PAIRING"
);
_burn(firstTokenId);
_burn(secondTokenId);
uint256 doublePanelTokenId = 3000 + _doublePanelTokens.current();
maps.tokenSeed[doublePanelTokenId] = SeedPhraseUtils.generateSeed(doublePanelTokenId, config.vrfRandomValue);
uint8 rarity1 = SeedPhraseUtils.getRarityRating(_getTokenSeed(firstTokenId));
uint8 rarity2 = SeedPhraseUtils.getRarityRating(_getTokenSeed(secondTokenId));
maps.doubleTokenRarity[doublePanelTokenId] = (rarity1 > rarity2 ? rarity1 : rarity2);
_mint(msg.sender, doublePanelTokenId);
maps.burnedTokensPairings[doublePanelTokenId] = [firstTokenId, secondTokenId];
_doublePanelTokens.increment();
emit Burnt(msg.sender, firstTokenId, secondTokenId, doublePanelTokenId);
}
function airdropGenesisSketch() public nonReentrant onlyAdmin {
require(!config.isGsAirdropComplete, "SP:ALREADY_AIRDROPPED");
require(config.bipWordsShuffled && config.vrfNumberGenerated, "SP:ENV_NOT_INIT");
uint256 airdropAmount = genesisSketchAddresses.length;
require(totalSupply() + airdropAmount <= params.maxTotalSupply, "NilPass:MAX_ALLOCATION_REACHED");
for (uint256 i = 0; i < airdropAmount; i++) {
uint256 tokenId = _tokenIds.current();
maps.tokenSeed[tokenId] = SeedPhraseUtils.generateSeed(tokenId, config.vrfRandomValue);
_mint(genesisSketchAddresses[i], tokenId);
_tokenIds.increment();
}
config.isGsAirdropComplete = true;
}
function mintOrphanedPieces(uint256 amount, address addr) public nonReentrant onlyAdmin {
require(totalMintsAvailable() == 0, "SP:MINT_NOT_OVER");
uint256 currentSupply = _tokenIds.current() - 1;
config.doubleBurnTokens = derivativeParams.maxTotalSupply - currentSupply;
require(config.doubleBurnTokens >= amount, "SP:NOT_ENOUGH_ORPHANS");
require(currentSupply + amount <= params.maxTotalSupply, "NilPass:MAX_ALLOCATION_REACHED");
for (uint256 i = 0; i < amount; i++) {
uint256 tokenId = _tokenIds.current();
require(tokenId <= params.maxTotalSupply, "SP:TOKEN_TOO_HIGH");
maps.tokenSeed[tokenId] = SeedPhraseUtils.generateSeed(tokenId, config.vrfRandomValue);
_mint(addr, tokenId);
_tokenIds.increment();
}
config.doubleBurnTokens -= amount;
}
function totalMintsAvailable() public view override returns (uint256) {
uint256 totalAvailable = derivativeParams.maxTotalSupply - totalSupply();
if (block.timestamp > config.publicSaleLaunchTime + 18 hours) {
uint256 doubleBurn = (block.timestamp - (config.publicSaleLaunchTime + 18 hours)) / 1 minutes;
totalAvailable = totalAvailable > doubleBurn ? totalAvailable - doubleBurn : 0;
}
return totalAvailable;
}
function getDoubleBurnedTokens() external view returns (uint256) {
return config.doubleBurnTokens;
}
function _getMaxMintPerWallet() internal view returns (uint128) {
return _isPublicSaleActive() ? config.maxPublicMint : params.maxMintAllowance;
}
function isValidPairing(uint16 first, uint16 second) public view returns (bool) {
return maps.doubleWordPairings[first] == second;
}
function amendPairings(uint16[][] calldata pairings) external onlyAdmin {
for (uint16 i = 0; i < pairings.length; i++) {
if (pairings[i].length != 2) {
continue;
}
maps.doubleWordPairings[pairings[i][0]] = pairings[i][1];
}
}
function shuffleBipWords() external onlyAdmin {
require(config.vrfNumberGenerated, "SP:VRF_NOT_CALLED");
require(!config.bipWordsShuffled, "SP:ALREADY_SHUFFLED");
bipWordIds = SeedPhraseUtils.shuffleBipWords(config.vrfRandomValue);
config.bipWordsShuffled = true;
}
}
文件 26 的 30:SeedPhrasePricing.sol
pragma solidity >=0.8.4;
import "../core/NilPassCore.sol";
abstract contract SeedPhrasePricing is NilPassCore {
uint256 preSalePrice;
uint256 publicSalePrice;
constructor(
string memory name,
string memory symbol,
IN n,
DerivativeParameters memory derivativeParams,
uint256 preSalePrice_,
uint256 publicSalePrice_,
address masterMint,
address dao
) NilPassCore(name, symbol, n, derivativeParams, masterMint, dao) {
preSalePrice = preSalePrice_;
publicSalePrice = publicSalePrice_;
}
enum PreSaleType {
GenesisSketch,
OG,
GM,
Karma,
N,
None
}
function _canMintPresale(
address addr,
uint256 amount,
bytes memory data
) internal view virtual returns (bool, PreSaleType);
function _isPublicSaleActive() internal view virtual returns (bool);
function getNextPriceForNHoldersInWei(
uint256 numberOfMints,
address account,
bytes memory data
) public view override returns (uint256) {
(bool preSaleEligible, ) = _canMintPresale(account, numberOfMints, data);
uint256 price = preSaleEligible && !_isPublicSaleActive() ? preSalePrice : publicSalePrice;
return numberOfMints * price;
}
function getNextPriceForOpenMintInWei(
uint256 numberOfMints,
address account,
bytes memory data
) public view override returns (uint256) {
(bool preSaleEligible, ) = _canMintPresale(account, numberOfMints, data);
uint256 price = preSaleEligible && !_isPublicSaleActive() ? preSalePrice : publicSalePrice;
return numberOfMints * price;
}
}
文件 27 的 30:SeedPhraseUtils.sol
pragma solidity >=0.8.4;
import "@openzeppelin/contracts/utils/Strings.sol";
import "../interfaces/IKarmaScore.sol";
import "./NilProtocolUtils.sol";
import "../libraries/NilProtocolUtils.sol";
library SeedPhraseUtils {
using Strings for uint256;
using Strings for uint16;
using Strings for uint8;
struct Random {
uint256 seed;
uint256 offsetBit;
}
struct Colors {
string background;
string panel;
string panel2;
string panelStroke;
string selectedCircleStroke;
string selectedCircleFill;
string selectedCircleFill2;
string negativeCircleStroke;
string negativeCircleFill;
string blackOrWhite;
string dynamicOpacity;
string backgroundCircle;
}
struct Attrs {
bool showStroke;
bool border;
bool showPanel;
bool backgroundSquare;
bool bigBackgroundCircle;
bool showGrid;
bool backgroundCircles;
bool greyscale;
bool doublePanel;
uint16 bipWordId;
uint16 secondBipWordId;
}
uint8 internal constant strokeWeight = 7;
uint16 internal constant segmentSize = 100;
uint16 internal constant radius = 50;
uint16 internal constant padding = 10;
uint16 internal constant viewBox = 1600;
uint16 internal constant panelWidth = segmentSize * 4;
uint16 internal constant panelHeight = segmentSize * 10;
uint16 internal constant singlePanelX = (segmentSize * 6);
uint16 internal constant doublePanel1X = (segmentSize * 3);
uint16 internal constant doublePanel2X = doublePanel1X + (segmentSize * 6);
uint16 internal constant panelY = (segmentSize * 3);
function generateSeed(uint256 tokenId, uint256 vrfRandomValue) external view returns (bytes32) {
return keccak256(abi.encode(tokenId, block.timestamp, block.difficulty, vrfRandomValue));
}
function _shouldAddTrait(
bool isTrue,
bytes memory trueName,
bytes memory falseName,
uint8 prevRank,
uint8 newRank,
bytes memory traits
) internal pure returns (bytes memory, uint8) {
if (isTrue) {
traits = abi.encodePacked(traits, ',{"value": "', trueName, '"}');
}
else if (falseName.length != 0) {
traits = abi.encodePacked(traits, ',{"value": "', falseName, '"}');
}
return (traits, (isTrue ? newRank : prevRank));
}
function tokenTraits(Attrs memory attributes) internal pure returns (bytes memory traits, uint8 rarityRating) {
rarityRating = 0;
traits = abi.encodePacked("[");
if (attributes.doublePanel) {
traits = abi.encodePacked(
traits,
'{"trait_type": "Double Panel BIP39 IDs", "value": "',
attributes.bipWordId.toString(),
" - ",
attributes.secondBipWordId.toString(),
'"},',
'{"value": "Double Panel"}'
);
} else {
traits = abi.encodePacked(
traits,
'{"trait_type": "BIP39 ID", "display_type": "number", "max_value": 2048, "value": ',
attributes.bipWordId.toString(),
"}"
);
}
(traits, rarityRating) = _shouldAddTrait(
!attributes.showStroke,
"No Stroke",
"OG Stroke",
rarityRating,
1,
traits
);
(traits, rarityRating) = _shouldAddTrait(attributes.border, "Border", "", rarityRating, 2, traits);
(traits, rarityRating) = _shouldAddTrait(
!attributes.showPanel,
"No Panel",
"OG Panel",
rarityRating,
3,
traits
);
(traits, rarityRating) = _shouldAddTrait(
attributes.backgroundSquare,
"Group Square",
"",
rarityRating,
4,
traits
);
(traits, rarityRating) = _shouldAddTrait(
attributes.bigBackgroundCircle,
"Group Circle",
"",
rarityRating,
5,
traits
);
(traits, rarityRating) = _shouldAddTrait(attributes.showGrid, "Caged", "", rarityRating, 6, traits);
(traits, rarityRating) = _shouldAddTrait(
attributes.backgroundCircles,
"Bubblewrap",
"",
rarityRating,
7,
traits
);
(traits, rarityRating) = _shouldAddTrait(attributes.greyscale, "Monochrome", "", rarityRating, 8, traits);
traits = abi.encodePacked(traits, "]");
}
function tokenAttributes(
uint16 bipWordId,
uint16 secondBipWordId,
Random memory random,
uint8 predefinedRarity
) internal pure returns (Attrs memory attributes) {
attributes = Attrs({
showStroke: (predefinedRarity == 1) ? false : _boolPercentage(random, 70),
border: (predefinedRarity == 2) ? true : _boolPercentage(random, 30),
showPanel: (predefinedRarity == 3) ? false : _boolPercentage(random, 80),
backgroundSquare: (predefinedRarity == 4) ? true : _boolPercentage(random, 18),
bigBackgroundCircle: (predefinedRarity == 5) ? true : _boolPercentage(random, 12),
showGrid: (predefinedRarity == 6) ? true : _boolPercentage(random, 6),
backgroundCircles: (predefinedRarity == 7) ? true : _boolPercentage(random, 4),
greyscale: (predefinedRarity == 8) ? true : _boolPercentage(random, 2),
bipWordId: bipWordId,
doublePanel: (secondBipWordId > 0),
secondBipWordId: secondBipWordId
});
if (attributes.showGrid || attributes.greyscale) {
attributes.showStroke = true;
}
if (attributes.backgroundCircles) {
attributes.showGrid = false;
}
if (attributes.bigBackgroundCircle || attributes.backgroundSquare) {
attributes.border = false;
if (attributes.bigBackgroundCircle) {
attributes.backgroundSquare = false;
}
}
}
function _transformTokenId(uint256 tokenId) internal pure returns (uint8[4] memory tokenArray, string memory) {
bytes memory tokenString;
uint8 digit;
for (int8 i = 3; i >= 0; i--) {
digit = uint8(tokenId % 10);
if (tokenId > 0) {
tokenId = tokenId / 10;
tokenArray[uint8(i)] = digit;
}
tokenString = abi.encodePacked(digit.toString(), tokenString);
}
return (tokenArray, string(tokenString));
}
function _renderText(string memory text, string memory color) internal pure returns (bytes memory svg) {
svg = abi.encodePacked(
"<text x='1500' y='1500' text-anchor='end' style='font:700 36px "Courier New";fill:",
color,
";opacity:.4'>#",
text,
"</text>"
);
return svg;
}
function _backgroundShapeSizing(Random memory random, Attrs memory attributes)
internal
pure
returns (uint16, uint16)
{
uint256 idx;
if (!attributes.doublePanel && attributes.showPanel) {
uint16[2][6] memory defaultSizing = [
[1275, 200],
[1150, 375],
[900, 300],
[925, 225],
[850, 150],
[775, 125]
];
idx = SeedPhraseUtils._next(random, 0, defaultSizing.length);
return (defaultSizing[idx][0], defaultSizing[idx][1]);
}
if (attributes.bigBackgroundCircle) {
uint16[2][4] memory restrictedCircleDimensions = [[1150, 150], [1275, 200], [1300, 100], [1350, 200]];
idx = SeedPhraseUtils._next(random, 0, restrictedCircleDimensions.length);
return (restrictedCircleDimensions[idx][0], restrictedCircleDimensions[idx][1]);
}
uint16[2][4] memory restrictedSquareDimensions = [[1150, 50], [1100, 125], [1275, 200], [1300, 150]];
idx = SeedPhraseUtils._next(random, 0, restrictedSquareDimensions.length);
return (restrictedSquareDimensions[idx][0], restrictedSquareDimensions[idx][1]);
}
function _getStrokeStyle(
bool showStroke,
string memory color,
string memory opacity,
uint8 customStrokeWeight
) internal pure returns (bytes memory strokeStyle) {
if (showStroke) {
strokeStyle = abi.encodePacked(
" style='stroke-opacity:",
opacity,
";stroke:",
color,
";stroke-width:",
customStrokeWeight.toString(),
"' "
);
return strokeStyle;
}
}
function _getPalette(Random memory random, Attrs memory attributes) internal pure returns (Colors memory) {
string[6] memory selectedPallet;
uint8[6] memory lumosity;
if (attributes.greyscale) {
selectedPallet = ["#f8f9fa", "#c3c4c4", "#909091", "#606061", "#343435", "#0a0a0b"];
lumosity = [249, 196, 144, 96, 52, 10];
} else {
uint256 randPalette = SeedPhraseUtils._next(random, 0, 25);
if (randPalette == 0) {
selectedPallet = ["#ffe74c", "#ff5964", "#ffffff", "#6bf178", "#35a7ff", "#5b3758"];
lumosity = [225, 125, 255, 204, 149, 65];
} else if (randPalette == 1) {
selectedPallet = ["#ff0000", "#ff8700", "#e4ff33", "#a9ff1f", "#0aefff", "#0a33ff"];
lumosity = [54, 151, 235, 221, 191, 57];
} else if (randPalette == 2) {
selectedPallet = ["#f433ab", "#cb04a5", "#934683", "#65334d", "#2d1115", "#e0e2db"];
lumosity = [101, 58, 91, 64, 23, 225];
} else if (randPalette == 3) {
selectedPallet = ["#f08700", "#f6aa28", "#f9d939", "#00a6a6", "#bbdef0", "#23556c"];
lumosity = [148, 177, 212, 131, 216, 76];
} else if (randPalette == 4) {
selectedPallet = ["#f7e6de", "#e5b59e", "#cb7d52", "#bb8f77", "#96624a", "#462b20"];
lumosity = [233, 190, 138, 151, 107, 48];
} else if (randPalette == 5) {
selectedPallet = ["#f61379", "#d91cbc", "#da81ee", "#5011e4", "#4393ef", "#8edef6"];
lumosity = [75, 80, 156, 46, 137, 207];
} else if (randPalette == 6) {
selectedPallet = ["#010228", "#006aa3", "#005566", "#2ac1df", "#82dded", "#dbf5fa"];
lumosity = [5, 88, 68, 163, 203, 240];
} else if (randPalette == 7) {
selectedPallet = ["#f46036", "#5b85aa", "#414770", "#372248", "#171123", "#f7f5fb"];
lumosity = [124, 127, 73, 41, 20, 246];
} else if (randPalette == 8) {
selectedPallet = ["#393d3f", "#fdfdff", "#c6c5b9", "#62929e", "#546a7b", "#c52233"];
lumosity = [60, 253, 196, 137, 103, 70];
} else if (randPalette == 9) {
selectedPallet = ["#002626", "#0e4749", "#95c623", "#e55812", "#efe7da", "#8ddbe0"];
lumosity = [30, 59, 176, 113, 232, 203];
} else if (randPalette == 10) {
selectedPallet = ["#03071e", "#62040d", "#d00000", "#e85d04", "#faa307", "#ffcb47"];
lumosity = [8, 25, 44, 116, 170, 205];
} else if (randPalette == 11) {
selectedPallet = ["#f56a00", "#ff931f", "#ffd085", "#20003d", "#7b2cbf", "#c698eb"];
lumosity = [128, 162, 213, 11, 71, 168];
} else if (randPalette == 12) {
selectedPallet = ["#800016", "#ffffff", "#ff002b", "#407ba7", "#004e89", "#00043a"];
lumosity = [29, 255, 57, 114, 66, 7];
} else if (randPalette == 13) {
selectedPallet = ["#d6d6d6", "#f9f7dc", "#ffee32", "#ffd100", "#202020", "#6c757d"];
lumosity = [214, 245, 228, 204, 32, 116];
} else if (randPalette == 14) {
selectedPallet = ["#fff5d6", "#ccc5b9", "#403d39", "#252422", "#eb5e28", "#bb4111"];
lumosity = [245, 198, 61, 36, 120, 87];
} else if (randPalette == 15) {
selectedPallet = ["#0c0f0a", "#ff206e", "#fbff12", "#41ead4", "#6c20fd", "#ffffff"];
lumosity = [14, 85, 237, 196, 224, 255];
} else if (randPalette == 16) {
selectedPallet = ["#fdd8d8", "#f67979", "#e51010", "#921314", "#531315", "#151315"];
lumosity = [224, 148, 61, 46, 33, 20];
} else if (randPalette == 17) {
selectedPallet = ["#000814", "#002752", "#0066cc", "#f5bc00", "#ffd60a", "#ffee99"];
lumosity = [7, 34, 88, 187, 208, 235];
} else if (randPalette == 18) {
selectedPallet = ["#010b14", "#022d4f", "#fdfffc", "#2ec4b6", "#e71d36", "#ff990a"];
lumosity = [10, 38, 254, 163, 74, 164];
} else if (randPalette == 19) {
selectedPallet = ["#fd650d", "#d90368", "#820263", "#291720", "#06efa9", "#0d5943"];
lumosity = [127, 56, 36, 27, 184, 71];
} else if (randPalette == 20) {
selectedPallet = ["#002914", "#005200", "#34a300", "#70e000", "#aef33f", "#e0ff85"];
lumosity = [31, 59, 128, 184, 215, 240];
} else if (randPalette == 21) {
selectedPallet = ["#001413", "#fafffe", "#6f0301", "#a92d04", "#f6b51d", "#168eb6"];
lumosity = [16, 254, 26, 68, 184, 119];
} else if (randPalette == 22) {
selectedPallet = ["#6a1f10", "#d53e20", "#f7d1ca", "#c4f3fd", "#045362", "#fffbfa"];
lumosity = [46, 92, 217, 234, 67, 252];
} else if (randPalette == 23) {
selectedPallet = ["#6b42ff", "#a270ff", "#dda1f7", "#ffd6eb", "#ff8fb2", "#f56674"];
lumosity = [88, 133, 180, 224, 169, 133];
} else if (randPalette == 24) {
selectedPallet = ["#627132", "#273715", "#99a271", "#fefae1", "#e0a35c", "#bf6b21"];
lumosity = [105, 49, 157, 249, 171, 120];
}
}
return _shufflePallet(random, selectedPallet, lumosity, attributes);
}
function _shufflePallet(
Random memory random,
string[6] memory hexColors,
uint8[6] memory lumaValues,
Attrs memory attributes
) internal pure returns (Colors memory) {
for (uint8 i = 0; i < hexColors.length; i++) {
uint256 n = i + SeedPhraseUtils._next(random, 0, (hexColors.length - i));
string memory tempHex = hexColors[n];
uint8 tempLuma = lumaValues[n];
hexColors[n] = hexColors[i];
hexColors[i] = tempHex;
lumaValues[n] = lumaValues[i];
lumaValues[i] = tempLuma;
}
Colors memory pallet = Colors({
background: hexColors[0],
panel: hexColors[1],
panel2: "",
panelStroke: hexColors[2],
selectedCircleStroke: hexColors[2],
negativeCircleStroke: hexColors[3],
negativeCircleFill: hexColors[4],
selectedCircleFill: hexColors[5],
selectedCircleFill2: "",
backgroundCircle: "",
blackOrWhite: lumaValues[0] < 150 ? "#fff" : "#000",
dynamicOpacity: lumaValues[0] < 150 ? "0.08" : "0.04"
});
if (attributes.doublePanel) {
pallet.panel2 = pallet.selectedCircleFill;
pallet.selectedCircleFill2 = pallet.panel;
}
if (attributes.bigBackgroundCircle) {
pallet.backgroundCircle = pallet.background;
pallet.background = pallet.panel;
pallet.blackOrWhite = lumaValues[1] < 150 ? "#fff" : "#000";
pallet.dynamicOpacity = lumaValues[1] < 150 ? "0.08" : "0.04";
}
return pallet;
}
function _next(
Random memory random,
uint256 min,
uint256 max
) internal pure returns (uint256 result) {
uint256 newSeed = random.seed;
uint256 newOffset = random.offsetBit + 3;
uint256 maxOffset = 4;
uint256 mask = 0xf;
if (max > 0xfffff) {
mask = 0xffffff;
maxOffset = 24;
} else if (max > 0xffff) {
mask = 0xfffff;
maxOffset = 20;
} else if (max > 0xfff) {
mask = 0xffff;
maxOffset = 16;
} else if (max > 0xff) {
mask = 0xfff;
maxOffset = 12;
} else if (max > 0xf) {
mask = 0xff;
maxOffset = 8;
}
if (newOffset > (256 - maxOffset)) {
newOffset = 0;
newSeed = uint256(keccak256(abi.encode(newSeed)));
}
uint256 offseted = (newSeed >> newOffset);
uint256 part = offseted & mask;
result = min + (part % (max - min));
random.seed = newSeed;
random.offsetBit = newOffset;
}
function _boolPercentage(Random memory random, uint256 percentage) internal pure returns (bool) {
return (SeedPhraseUtils._next(random, 0, 100) < percentage);
}
function render(SeedPhraseUtils.Random memory random, SeedPhraseUtils.Attrs memory attributes)
external
pure
returns (string memory)
{
SeedPhraseUtils.Colors memory pallet = SeedPhraseUtils._getPalette(random, attributes);
bytes memory svg = abi.encodePacked(
"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1600 1600'><path fill='",
pallet.background,
"' ",
SeedPhraseUtils._getStrokeStyle(attributes.border, pallet.blackOrWhite, "0.3", 50),
" d='M0 0h1600v1600H0z'/>",
" <pattern id='panelCircles' x='0' y='0' width='.25' height='.1' patternUnits='objectBoundingBox'>",
"<circle cx='50' cy='50' r='40' fill='",
pallet.negativeCircleFill,
"' ",
SeedPhraseUtils._getStrokeStyle(attributes.showStroke, pallet.negativeCircleStroke, "1", strokeWeight),
" /></pattern>"
);
if (attributes.backgroundCircles) {
svg = abi.encodePacked(
svg,
"<pattern id='backgroundCircles' x='0' y='0' width='100' height='100'",
" patternUnits='userSpaceOnUse'><circle cx='50' cy='50' r='40' fill='",
pallet.blackOrWhite,
"' style='fill-opacity: ",
pallet.dynamicOpacity,
";'></circle></pattern><path fill='url(#backgroundCircles)' d='M0 0h1600v1600H0z'/>"
);
} else if (attributes.showGrid) {
svg = abi.encodePacked(
svg,
"<pattern id='grid' x='0' y='0' width='100' height='100'",
" patternUnits='userSpaceOnUse'><rect x='0' y='0' width='100' height='100' fill='none' ",
SeedPhraseUtils._getStrokeStyle(true, pallet.blackOrWhite, pallet.dynamicOpacity, strokeWeight),
" /></pattern><path fill='url(#grid)' d='M0 0h1600v1600H0z'/>"
);
}
if (attributes.bigBackgroundCircle) {
(uint16 shapeSize, uint16 stroke) = SeedPhraseUtils._backgroundShapeSizing(random, attributes);
svg = abi.encodePacked(
svg,
"<circle cx='800' cy='800' r='",
(shapeSize / 2).toString(),
"' fill='",
pallet.backgroundCircle,
"' stroke='",
pallet.negativeCircleStroke,
"' style='stroke-width:",
stroke.toString(),
";stroke-opacity:0.3'/>"
);
} else if (attributes.backgroundSquare) {
(uint16 shapeSize, uint16 stroke) = SeedPhraseUtils._backgroundShapeSizing(random, attributes);
uint16 centerSquare = ((viewBox - shapeSize) / 2);
svg = abi.encodePacked(
svg,
"<rect x='",
centerSquare.toString(),
"' y='",
centerSquare.toString(),
"' width='",
shapeSize.toString(),
"' height='",
shapeSize.toString(),
"' fill='",
pallet.backgroundCircle,
"' stroke='",
pallet.negativeCircleStroke,
"' style='stroke-width:",
stroke.toString(),
";stroke-opacity:0.3'/>"
);
}
if (attributes.doublePanel) {
(uint8[4] memory firstBipIndexArray, string memory firstBipIndexStr) = SeedPhraseUtils._transformTokenId(
attributes.bipWordId
);
(uint8[4] memory secondBipIndexArray, string memory secondBipIndexStr) = SeedPhraseUtils._transformTokenId(
attributes.secondBipWordId
);
svg = abi.encodePacked(
svg,
_renderSinglePanel(firstBipIndexArray, attributes, pallet, doublePanel1X, false),
_renderSinglePanel(secondBipIndexArray, attributes, pallet, doublePanel2X, true)
);
bytes memory combinedText = abi.encodePacked(firstBipIndexStr, " - #", secondBipIndexStr);
svg = abi.encodePacked(
svg,
SeedPhraseUtils._renderText(string(combinedText), pallet.blackOrWhite),
"</svg>"
);
}
else {
(uint8[4] memory bipIndexArray, string memory bipIndexStr) = SeedPhraseUtils._transformTokenId(
attributes.bipWordId
);
svg = abi.encodePacked(svg, _renderSinglePanel(bipIndexArray, attributes, pallet, singlePanelX, false));
svg = abi.encodePacked(svg, SeedPhraseUtils._renderText(bipIndexStr, pallet.blackOrWhite), "</svg>");
}
return string(svg);
}
function _renderSinglePanel(
uint8[4] memory bipIndexArray,
SeedPhraseUtils.Attrs memory attributes,
SeedPhraseUtils.Colors memory pallet,
uint16 panelX,
bool secondPanel
) internal pure returns (bytes memory panelSvg) {
bool squareEdges = (attributes.doublePanel && attributes.backgroundSquare);
if (attributes.showPanel) {
panelSvg = abi.encodePacked(
"<rect x='",
(panelX - padding).toString(),
"' y='",
(panelY - padding).toString(),
"' width='",
(panelWidth + (padding * 2)).toString(),
"' height='",
(panelHeight + (padding * 2)).toString(),
"' rx='",
(squareEdges ? 0 : radius).toString(),
"' fill='",
(secondPanel ? pallet.panel2 : pallet.panel),
"' ",
SeedPhraseUtils._getStrokeStyle(attributes.showStroke, pallet.panelStroke, "1", strokeWeight),
"/>"
);
}
panelSvg = abi.encodePacked(
panelSvg,
"<path fill='url(#panelCircles)' d='M",
panelX.toString(),
" ",
panelY.toString(),
"h",
panelWidth.toString(),
"v",
panelHeight.toString(),
"H",
panelX.toString(),
"z'/>"
);
panelSvg = abi.encodePacked(
panelSvg,
_renderSelectedCircles(bipIndexArray, pallet, attributes.showStroke, panelX, secondPanel)
);
}
function _renderSelectedCircles(
uint8[4] memory bipIndexArray,
SeedPhraseUtils.Colors memory pallet,
bool showStroke,
uint16 panelX,
bool secondPanel
) internal pure returns (bytes memory svg) {
for (uint8 i = 0; i < bipIndexArray.length; i++) {
svg = abi.encodePacked(
svg,
"<circle cx='",
(panelX + (segmentSize * i) + radius).toString(),
"' cy='",
(panelY + (segmentSize * bipIndexArray[i]) + radius).toString(),
"' r='41' fill='",
(secondPanel ? pallet.selectedCircleFill2 : pallet.selectedCircleFill),
"' ",
SeedPhraseUtils._getStrokeStyle(showStroke, pallet.selectedCircleStroke, "1", strokeWeight),
" />"
);
}
}
function getRarityRating(bytes32 tokenSeed) external pure returns (uint8) {
SeedPhraseUtils.Random memory random = SeedPhraseUtils.Random({ seed: uint256(tokenSeed), offsetBit: 0 });
(, uint8 rarityRating) = SeedPhraseUtils.tokenTraits(SeedPhraseUtils.tokenAttributes(0, 0, random, 0));
return rarityRating;
}
function getTraitsAndAttributes(
uint16 bipWordId,
uint16 secondBipWordId,
uint8 rarityValue,
SeedPhraseUtils.Random memory random
) external pure returns (bytes memory, SeedPhraseUtils.Attrs memory) {
SeedPhraseUtils.Attrs memory attributes = SeedPhraseUtils.tokenAttributes(
bipWordId,
secondBipWordId,
random,
rarityValue
);
(bytes memory traits, ) = SeedPhraseUtils.tokenTraits(attributes);
return (traits, attributes);
}
function getKarma(IKarmaScore karma, bytes memory data, address account) external view returns (uint256) {
if (data.length > 0) {
(, uint256 karmaScore, ) = abi.decode(data, (address, uint256, bytes32[]));
if (karma.verify(account, karmaScore, data)) {
return account == address(0) ? 1000 : karmaScore;
}
}
return 1000;
}
function shuffleBipWords(uint256 randomValue) external pure returns (uint16[] memory) {
uint16 size = 2048;
uint16[] memory result = new uint16[](size);
for (uint16 i = 0; i < size; i++) {
result[i] = i + 1;
}
bytes32 random = keccak256(abi.encodePacked(randomValue));
uint16 lastItem = size - 1;
for (uint16 i = 1; i < size - 1; i++) {
uint16 selectedItem = uint16(uint256(random) % lastItem);
(result[lastItem], result[selectedItem]) = (result[selectedItem], result[lastItem]);
lastItem--;
random = keccak256(abi.encodePacked(random));
}
return result;
}
function getDescriptionPt1() internal pure returns (string memory) {
return "\"Seed Phrase is a 'Crypto Native' *fully* on-chain collection.\\n\\nA '*SEED*' is unique, it represents a single word from the BIP-0039 word list (the most commonly used word list to generate a seed/recovery phrase, think of it as a dictionary that only holds 2048 words).\\n\\n***Your 'SEED*' = *Your 'WORD*' in the list.** \\nClick [here](https://www.seedphrase.codes/token?id=";
}
function getDescriptionPt2() internal pure returns (string memory) {
return ") to decipher *your 'SEED*' and find out which word it translates to!\\n\\nFor Licensing, T&Cs or any other info, please visit: [www.seedphrase.codes](https://www.seedphrase.codes/).\"";
}
function getTokenURI(string memory output, bytes memory traits, uint256 tokenId) external pure returns (string memory) {
return string(
abi.encodePacked(
"data:application/json;base64,",
NilProtocolUtils.base64encode(
bytes(
string(
abi.encodePacked(
'{"name": "Seed Phrase #',
NilProtocolUtils.stringify(tokenId),
'", "image": "data:image/svg+xml;base64,',
NilProtocolUtils.base64encode(bytes(output)),
'", "attributes": ',
traits,
', "description": ',
getDescriptionPt1(),
tokenId.toString(),
getDescriptionPt2(),
"}"
)
)
)
)
)
);
}
}
文件 28 的 30:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
文件 29 的 30:VRFConsumerBase.sol
pragma solidity ^0.8.0;
import "./interfaces/LinkTokenInterface.sol";
import "./VRFRequestIDBase.sol";
abstract contract VRFConsumerBase is VRFRequestIDBase {
function fulfillRandomness(
bytes32 requestId,
uint256 randomness
)
internal
virtual;
uint256 constant private USER_SEED_PLACEHOLDER = 0;
function requestRandomness(
bytes32 _keyHash,
uint256 _fee
)
internal
returns (
bytes32 requestId
)
{
LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, USER_SEED_PLACEHOLDER));
uint256 vRFSeed = makeVRFInputSeed(_keyHash, USER_SEED_PLACEHOLDER, address(this), nonces[_keyHash]);
nonces[_keyHash] = nonces[_keyHash] + 1;
return makeRequestId(_keyHash, vRFSeed);
}
LinkTokenInterface immutable internal LINK;
address immutable private vrfCoordinator;
mapping(bytes32 => uint256 ) private nonces;
constructor(
address _vrfCoordinator,
address _link
) {
vrfCoordinator = _vrfCoordinator;
LINK = LinkTokenInterface(_link);
}
function rawFulfillRandomness(
bytes32 requestId,
uint256 randomness
)
external
{
require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill");
fulfillRandomness(requestId, randomness);
}
}
文件 30 的 30:VRFRequestIDBase.sol
pragma solidity ^0.8.0;
contract VRFRequestIDBase {
function makeVRFInputSeed(
bytes32 _keyHash,
uint256 _userSeed,
address _requester,
uint256 _nonce
)
internal
pure
returns (
uint256
)
{
return uint256(keccak256(abi.encode(_keyHash, _userSeed, _requester, _nonce)));
}
function makeRequestId(
bytes32 _keyHash,
uint256 _vRFInputSeed
)
internal
pure
returns (
bytes32
)
{
return keccak256(abi.encodePacked(_keyHash, _vRFInputSeed));
}
}
{
"compilationTarget": {
"contracts/seed-phrases/SeedPhrase.sol": "SeedPhrase"
},
"evmVersion": "berlin",
"libraries": {
"contracts/libraries/SeedPhraseUtils.sol:SeedPhraseUtils": "0x0612405007bef3dcb751057819480e89f32a03e0"
},
"metadata": {
"bytecodeHash": "none",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 300
},
"remappings": []
}
[{"inputs":[{"components":[{"internalType":"address","name":"n","type":"address"},{"internalType":"address","name":"masterMint","type":"address"},{"internalType":"address","name":"dao","type":"address"},{"internalType":"address","name":"nOwnersRegistry","type":"address"},{"internalType":"address","name":"vrfCoordinator","type":"address"},{"internalType":"address","name":"linkToken","type":"address"},{"internalType":"address","name":"karmaAddress","type":"address"},{"internalType":"address","name":"rarible","type":"address"}],"internalType":"struct SeedPhrase.ContractAddresses","name":"contractAddresses","type":"tuple"},{"internalType":"bytes32","name":"_vrfKeyHash","type":"bytes32"},{"internalType":"uint256","name":"_linkFee","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"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":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"firstBurntToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"secondBurntToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"doublePaneledToken","type":"uint256"}],"name":"Burnt","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","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":"ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DAO_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_MULTI_MINT_AMOUNT","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_N_TOKEN_ID","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"airdropGenesisSketch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16[][]","name":"pairings","type":"uint16[][]"}],"name":"amendPairings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"firstTokenId","type":"uint256"},{"internalType":"uint256","name":"secondTokenId","type":"uint256"}],"name":"burnForDoublePanel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"canMint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"derivativeParams","outputs":[{"internalType":"bool","name":"onlyNHolders","type":"bool"},{"internalType":"bool","name":"supportsTokenId","type":"bool"},{"internalType":"uint16","name":"reservedAllowance","type":"uint16"},{"internalType":"uint128","name":"maxTotalSupply","type":"uint128"},{"internalType":"uint128","name":"maxMintAllowance","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDoubleBurnedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numberOfMints","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"getNextPriceForNHoldersInWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numberOfMints","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"getNextPriceForOpenMintInWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVrfSeed","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","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":"uint16","name":"first","type":"uint16"},{"internalType":"uint16","name":"second","type":"uint16"}],"name":"isValidPairing","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"karma","outputs":[{"internalType":"contract IKarmaScore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"masterMint","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint8","name":"amount","type":"uint8"},{"internalType":"uint256","name":"paid","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"addr","type":"address"}],"name":"mintOrphanedPieces","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"mintOwnerSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintParameters","outputs":[{"components":[{"internalType":"uint256","name":"reservedAllowance","type":"uint256"},{"internalType":"uint256","name":"maxTotalSupply","type":"uint256"},{"internalType":"uint256","name":"nHoldersMintsAvailable","type":"uint256"},{"internalType":"uint256","name":"openMintsAvailable","type":"uint256"},{"internalType":"uint256","name":"totalMintsAvailable","type":"uint256"},{"internalType":"uint256","name":"nHolderPriceInWei","type":"uint256"},{"internalType":"uint256","name":"openPriceInWei","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"maxMintAllowance","type":"uint256"},{"internalType":"bool","name":"onlyNHolders","type":"bool"},{"internalType":"bool","name":"supportsTokenId","type":"bool"}],"internalType":"struct INilPass.MintParams","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"mintTokenId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint256","name":"paid","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mintWithN","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintedOutsideNRange","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"n","outputs":[{"internalType":"contract IN","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nHoldersMintsAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nOwnerResolver","outputs":[{"internalType":"contract INOwnerResolver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openMintsAvailable","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":"enum SeedPhrasePricing.PreSaleType","name":"","type":"uint8"}],"name":"presaleLimits","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rarible","outputs":[{"internalType":"contract IRarible","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"uint256","name":"randomness","type":"uint256"}],"name":"rawFulfillRandomness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveMinted","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reservedAllowance","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_burnActiveState","type":"bool"}],"name":"setBurnActiveState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses","type":"address[]"}],"name":"setGenesisSketchAllowList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses","type":"address[]"}],"name":"setOgAllowList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"status","type":"bool"}],"name":"setOnlyNHolders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_preSaleActiveState","type":"bool"}],"name":"setPreSaleState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_time","type":"uint32"}],"name":"setPreSaleTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_publicSaleActiveState","type":"bool"}],"name":"setPublicSaleState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_time","type":"uint32"}],"name":"setPublicSaleTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_saleHaltedState","type":"bool"}],"name":"setSaleHaltedState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shuffleBipWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenSVG","outputs":[{"internalType":"string","name":"svg","type":"string"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalMintsAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]