编译器
0.8.20+commit.a1b79de6
文件 1 的 23:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 23:Base64.sol
pragma solidity ^0.8.0;
library Base64 {
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function encode(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return "";
string memory table = _TABLE;
string memory result = new string(4 * ((data.length + 2) / 3));
assembly {
let tablePtr := add(table, 1)
let resultPtr := add(result, 32)
for {
let dataPtr := data
let endPtr := add(data, mload(data))
} 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 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case 2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}
文件 3 的 23: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 的 23: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;
}
}
文件 5 的 23:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 6 的 23:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 7 的 23:IERC4906.sol
pragma solidity ^0.8.0;
import "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol";
import "lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol";
interface IERC4906 is IERC165, IERC721 {
event MetadataUpdate(uint256 _tokenId);
}
文件 8 的 23: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, bytes calldata data) external;
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 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);
}
文件 9 的 23: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);
function tokenByIndex(uint256 index) external view returns (uint256);
}
文件 10 的 23: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);
}
文件 11 的 23:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 12 的 23:IWarps.sol
pragma solidity ^0.8.17;
interface IWarps {
struct StoredWarp {
uint16[6] composites;
uint8[5] colorBands;
uint8[5] gradients;
uint8 divisorIndex;
uint16 seed;
}
struct Warp {
StoredWarp stored;
uint256 seed;
uint8 warpsCount;
bool hasManyWarps;
uint16 composite;
bool isRoot;
uint8 colorBand;
uint8 gradient;
}
struct Epoch {
bool committed;
bool revealed;
uint64 revealBlock;
uint128 randomness;
}
struct Warps {
mapping(uint256 => StoredWarp) all;
mapping(uint256 => Epoch) epochs;
uint32 minted;
uint32 burned;
uint32 currentEpoch;
}
event Sacrifice(uint256 indexed burnedId, uint256 indexed tokenId);
event Composite(uint256 indexed tokenId, uint256 indexed burnedId, uint8 indexed warps);
error NotAllowed();
error InvalidTokenCount();
error BlackWarp__InvalidWarp();
}
文件 13 的 23: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);
}
}
}
文件 14 的 23: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);
}
}
文件 15 的 23:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 16 的 23: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);
}
}
}
文件 17 的 23: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));
}
}
文件 18 的 23:Utilities.sol
pragma solidity ^0.8.17;
library Utilities {
function random(uint256 input, uint256 _max) internal pure returns (uint256) {
return (uint256(keccak256(abi.encodePacked(input))) % _max);
}
function random(uint256 input, string memory salt, uint256 _max) internal pure returns (uint256) {
return (uint256(keccak256(abi.encodePacked(input, salt))) % _max);
}
function uint2str(uint256 _i) internal pure returns (string memory _uintAsString) {
if (_i == 0) {
return "0";
}
uint256 j = _i;
uint256 len;
while (j != 0) {
++len;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint256 k = len;
while (_i != 0) {
k = k - 1;
uint8 temp = (48 + uint8(_i - (_i / 10) * 10));
bytes1 b1 = bytes1(temp);
bstr[k] = b1;
_i /= 10;
}
return string(bstr);
}
function minGt0(uint8 one, uint8 two) internal pure returns (uint8) {
return one > two ? two > 0 ? two : one : one;
}
function min(uint8 one, uint8 two) internal pure returns (uint8) {
return one < two ? one : two;
}
function max(uint8 one, uint8 two) internal pure returns (uint8) {
return one > two ? one : two;
}
function avg(uint8 one, uint8 two) internal pure returns (uint8 result) {
unchecked {
result = (one >> 1) + (two >> 1) + (one & two & 1);
}
}
function day(uint256 from, uint256 to) internal pure returns (uint24) {
return uint24((to - from) / 24 hours + 1);
}
}
文件 19 的 23:WARPS721.sol
pragma solidity ^0.8.0;
import "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol";
import "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol";
import "lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "lib/openzeppelin-contracts/contracts/utils/Address.sol";
import "lib/openzeppelin-contracts/contracts/utils/Context.sol";
import "lib/openzeppelin-contracts/contracts/utils/Strings.sol";
import "lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol";
import "../interfaces/IERC4906.sol";
contract WARPS721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable, IERC4906 {
error ERC721__InvalidApproval();
error ERC721__InvalidOwner();
error ERC721__InvalidToken();
error ERC721__NotAllowed();
error ERC721__TokenExists();
error ERC721__TransferToNonReceiver();
error ERC721__TransferToZero();
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;
mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
mapping(uint256 => uint256) private _ownedTokensIndex;
uint256[] private _allTokens;
mapping(uint256 => uint256) private _allTokensIndex;
constructor() {
_name = "Warps";
_symbol = "WARPS";
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId
|| interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
function balanceOf(address owner) public view virtual override returns (uint256) {
if (owner == address(0)) {
revert ERC721__InvalidOwner();
}
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
address owner = _ownerOf(tokenId);
if (owner == address(0)) {
revert ERC721__InvalidToken();
}
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) {
_requireMinted(tokenId);
return "";
}
function approve(address to, uint256 tokenId) public virtual override {
address owner = WARPS721.ownerOf(tokenId);
if (to == owner || (_msgSender() != owner && !isApprovedForAll(owner, _msgSender()))) {
revert ERC721__InvalidApproval();
}
_approve(to, tokenId);
}
function getApproved(uint256 tokenId) public view virtual override returns (address) {
_requireMinted(tokenId);
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_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 {
if (!_isApprovedOrOwner(_msgSender(), tokenId)) {
revert ERC721__NotAllowed();
}
_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 {
if (!_isApprovedOrOwner(_msgSender(), tokenId)) {
revert ERC721__NotAllowed();
}
_safeTransfer(from, to, tokenId, data);
}
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
_transfer(from, to, tokenId);
if (!_checkOnERC721Received(from, to, tokenId, data)) {
revert ERC721__TransferToNonReceiver();
}
}
function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
return _owners[tokenId];
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _ownerOf(tokenId) != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
address owner = WARPS721.ownerOf(tokenId);
return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == 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);
if (!_checkOnERC721Received(address(0), to, tokenId, data)) {
revert ERC721__TransferToNonReceiver();
}
}
function _safeMintVia(address to, address via, uint256 tokenId) internal virtual {
_safeMintVia(to, via, tokenId, "");
}
function _safeMintVia(address to, address via, uint256 tokenId, bytes memory data) internal virtual {
_mintVia(to, via, tokenId);
if (!_checkOnERC721Received(address(0), to, tokenId, data)) {
revert ERC721__TransferToNonReceiver();
}
}
function _mint(address to, uint256 tokenId) internal virtual {
_mintState(to, tokenId);
emit Transfer(address(0), to, tokenId);
_afterTokenTransfer(address(0), to, tokenId, 1);
}
function _mintVia(address to, address via, uint256 tokenId) internal virtual {
_mintState(to, tokenId);
emit Transfer(address(0), via, tokenId);
emit Transfer(via, to, tokenId);
_afterTokenTransfer(address(0), to, tokenId, 1);
}
function _mintState(address to, uint256 tokenId) internal virtual {
if (to == address(0)) {
revert ERC721__TransferToZero();
}
if (_exists(tokenId)) {
revert ERC721__TokenExists();
}
_beforeTokenTransfer(address(0), to, tokenId, 1);
if (_exists(tokenId)) {
revert ERC721__TokenExists();
}
unchecked {
_balances[to] += 1;
}
_owners[tokenId] = to;
}
function _burn(uint256 tokenId) internal virtual {
address owner = WARPS721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId, 1);
owner = WARPS721.ownerOf(tokenId);
delete _tokenApprovals[tokenId];
unchecked {
_balances[owner] -= 1;
}
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
_afterTokenTransfer(owner, address(0), tokenId, 1);
}
function _transfer(address from, address to, uint256 tokenId) internal virtual {
if (WARPS721.ownerOf(tokenId) != from) {
revert ERC721__InvalidOwner();
}
if (to == address(0)) {
revert ERC721__TransferToZero();
}
_beforeTokenTransfer(from, to, tokenId, 1);
if (WARPS721.ownerOf(tokenId) != from) {
revert ERC721__InvalidOwner();
}
delete _tokenApprovals[tokenId];
unchecked {
_balances[from] -= 1;
_balances[to] += 1;
}
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
_afterTokenTransfer(from, to, tokenId, 1);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(WARPS721.ownerOf(tokenId), to, tokenId);
}
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
if (owner == operator) {
revert ERC721__InvalidApproval();
}
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
function _requireMinted(uint256 tokenId) internal view virtual {
if (!_exists(tokenId)) {
revert ERC721__InvalidToken();
}
}
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data)
private
returns (bool)
{
if (_isContract(to)) {
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__TransferToNonReceiver();
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {
if (batchSize > 1) {
if (from != address(0)) {
_balances[from] -= batchSize;
}
if (to != address(0)) {
_balances[to] += batchSize;
}
}
if (from == address(0)) {
_addTokenToAllTokensEnumeration(firstTokenId);
} else if (from != to) {
_removeTokenFromOwnerEnumeration(from, firstTokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(firstTokenId);
} else if (to != from) {
_addTokenToOwnerEnumeration(to, firstTokenId);
}
}
function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {}
function _isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function totalSupply() public view virtual override returns (uint256) {
return _allTokens.length;
}
function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
if (index >= totalSupply()) {
revert ERC721__InvalidToken();
}
return _allTokens[index];
}
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
if (index >= balanceOf(owner)) {
revert ERC721__InvalidToken();
}
return _ownedTokens[owner][index];
}
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = 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 = balanceOf(from) - 1;
uint256 tokenIndex = _ownedTokensIndex[tokenId];
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId;
_ownedTokensIndex[lastTokenId] = tokenIndex;
}
delete _ownedTokens[from][lastTokenIndex];
delete _ownedTokensIndex[tokenId];
}
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId];
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId;
_allTokensIndex[lastTokenId] = tokenIndex;
_allTokens.pop();
delete _allTokensIndex[tokenId];
}
}
文件 20 的 23:WarpColors.sol
pragma solidity ^0.8.17;
library WarpColors {
function colors() public pure returns (string[5] memory) {
return [
"FF007A",
"855DCD",
"FF9900",
"52b043",
"1da1f2"
];
}
function getColorByIndex(uint8 _index) public pure returns (string memory) {
require(_index < 5, "Index out of bounds");
return colors()[_index];
}
function getIndexByColor(string memory _color) public pure returns (uint8) {
string[5] memory _colors = colors();
bytes32 colorHash = keccak256(abi.encodePacked(_color));
for (uint8 i = 0; i < 5; i++) {
if (keccak256(abi.encodePacked(_colors[i])) == colorHash) {
return i;
}
}
revert("Color not found");
}
}
文件 21 的 23:Warps.sol
pragma solidity ^0.8.17;
import "./interfaces/IWarps.sol";
import "./libraries/WarpsArt.sol";
import "./libraries/WarpsMetadata.sol";
import "./libraries/WarpColors.sol";
import "./libraries/Utilities.sol";
import "./standards/WARPS721.sol";
import "lib/openzeppelin-contracts/contracts/access/Ownable.sol";
import "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "lib/openzeppelin-contracts/contracts/security/Pausable.sol";
contract Warps is IWarps, WARPS721, Ownable, Pausable {
event MintPriceUpdated(uint256 newPrice);
event MintLimitUpdated(uint8 newLimit);
event PrizeClaimed(uint256 tokenId, address winner, uint256 amount);
event PrizePoolUpdated(uint256 totalDeposited);
event EmergencyWithdrawn(uint256 amount);
event TokensMinted(address indexed recipient, uint256 startTokenId, uint256 count);
event TokensComposited(uint256 indexed keptTokenId, uint256 indexed burnedTokenId);
event TokenBurned(uint256 indexed tokenId, address indexed burner);
event WinningColorIndexUpdated(uint8 newIndex);
event PaymentTokenSet(address indexed tokenAddress, uint256 mintPrice);
event OwnerMintSharePercentageUpdated(uint8 newPercentage);
event WinnerClaimPercentageUpdated(uint8 newPercentage);
event WinningColorSet(string colorHex, uint8 colorIndex);
event FreeMintUsed(address indexed recipient);
event TokensDeposited(address indexed sender, uint256 amount);
event ContractPaused(address indexed pauser);
event ContractUnpaused(address indexed unpauser);
uint8 public mintLimit = 4;
uint256 public constant MAX_COMPOSITE_LEVEL = 5;
uint256 public mintPrice;
uint256 public tokenMintId = 0;
IERC20 public paymentToken;
Warps _warpsData;
struct PrizePool {
uint32 lastWinnerClaim;
uint256 totalDeposited;
uint256 actualAvailable;
}
PrizePool public prizePool;
uint8 public winningColorIndex;
uint8 public ownerMintSharePercentage;
uint8 public winnerClaimPercentage;
mapping(address => bool) public hasUsedFreeMint;
struct TokenMetadata {
uint256 seed;
uint8[5] colorBands;
uint8[5] gradients;
}
mapping(uint256 => TokenMetadata) private _tokenMetadata;
struct Palette {
uint8 len;
uint24[3] colors;
}
mapping(uint256 => Palette) private _palette;
function getTotalDeposited() public view returns (uint256) {
return prizePool.totalDeposited;
}
function getActualAvailable() public view returns (uint256) {
return prizePool.actualAvailable;
}
constructor() Ownable() {
_warpsData.minted = 0;
_warpsData.burned = 0;
prizePool.lastWinnerClaim = 0;
prizePool.actualAvailable = 0;
winningColorIndex = 2;
ownerMintSharePercentage = 40;
winnerClaimPercentage = 5;
}
function pause() external onlyOwner {
_pause();
emit ContractPaused(msg.sender);
}
function unpause() external onlyOwner {
_unpause();
emit ContractUnpaused(msg.sender);
}
function depositTokens(uint256 amount) external whenNotPaused {
require(address(paymentToken) != address(0), "Payment token not set");
require(amount > 0, "Amount must be greater than 0");
uint256 allowance = paymentToken.allowance(msg.sender, address(this));
require(allowance >= amount, "Check allowance");
bool success = paymentToken.transferFrom(msg.sender, address(this), amount);
require(success, "ERC20 transfer failed");
prizePool.totalDeposited += amount;
prizePool.actualAvailable += amount;
emit TokensDeposited(msg.sender, amount);
emit PrizePoolUpdated(prizePool.totalDeposited);
}
function updateMintPrice(uint256 newPrice) external onlyOwner {
require(address(paymentToken) != address(0), "Payment token not set");
mintPrice = newPrice;
emit MintPriceUpdated(newPrice);
}
function setPaymentToken(address _tokenAddress, uint256 _mintPrice) external onlyOwner {
require(_tokenAddress != address(0), "Invalid token address");
paymentToken = IERC20(_tokenAddress);
mintPrice = _mintPrice;
emit PaymentTokenSet(_tokenAddress, _mintPrice);
emit MintPriceUpdated(_mintPrice);
}
function updateMintLimit(uint8 newLimit) external onlyOwner {
require(newLimit > 0 && newLimit <= 100, "Invalid limit");
mintLimit = newLimit;
emit MintLimitUpdated(newLimit);
}
function updateOwnerMintSharePercentage(uint8 newPercentage) external onlyOwner {
require(newPercentage < 100, "Percentage must be < 100");
ownerMintSharePercentage = newPercentage;
emit OwnerMintSharePercentageUpdated(newPercentage);
}
function updateWinnerClaimPercentage(uint8 newPercentage) external onlyOwner {
require(newPercentage > 0 && newPercentage <= 100, "Percentage must be 1-100");
winnerClaimPercentage = newPercentage;
emit WinnerClaimPercentageUpdated(newPercentage);
}
function _generateTokenRandomness(uint256 tokenId) internal {
uint256 seed = uint256(
keccak256(abi.encodePacked(block.timestamp, block.prevrandao, tokenId, msg.sender, _warpsData.minted))
) % type(uint128).max;
_tokenMetadata[tokenId].seed = seed;
uint8 n1 = uint8(seed & 0xFF);
uint8 n2 = uint8((seed >> 56) & 0xFF);
uint8 scaledN1 = uint8((uint256(n1) * 120) / 255);
uint8 scaledN2 = uint8((uint256(n2) * 100) / 255);
uint8 colorBand = scaledN1 > 20
? 0
: scaledN1 > 10 ? 1 : scaledN1 > 5 ? 2 : scaledN1 > 2 ? 3 : scaledN1 > 1 ? 4 : scaledN1 > 0 ? 5 : 6;
uint8 gradient = scaledN2 < 20 ? uint8(1 + (scaledN2 % 6)) : 0;
_warpsData.all[tokenId].colorBands[0] = colorBand;
_warpsData.all[tokenId].gradients[0] = gradient;
}
function mint(address recipient) external whenNotPaused {
require(address(paymentToken) != address(0), "Payment token not set");
require(recipient != address(0), "Invalid recipient");
uint256 requiredAmount = mintPrice;
require(requiredAmount > 0, "Mint price cannot be zero");
uint256 allowance = paymentToken.allowance(msg.sender, address(this));
require(allowance >= requiredAmount, "Check allowance");
bool success = paymentToken.transferFrom(msg.sender, address(this), requiredAmount);
require(success, "ERC20 transfer failed (minter -> contract)");
uint256 ownerShareAmount = (requiredAmount * ownerMintSharePercentage) / 100;
uint256 prizePoolAmount = requiredAmount - ownerShareAmount;
if (ownerShareAmount > 0) {
bool ownerTransferSuccess = paymentToken.transfer(owner(), ownerShareAmount);
require(ownerTransferSuccess, "ERC20 transfer failed (contract -> owner)");
}
prizePool.totalDeposited += requiredAmount;
prizePool.actualAvailable += prizePoolAmount;
emit PrizePoolUpdated(prizePool.totalDeposited);
uint256 startTokenId = tokenMintId;
for (uint256 i; i < mintLimit;) {
uint256 id = tokenMintId++;
StoredWarp storage warp = _warpsData.all[id];
warp.seed = uint16(id);
warp.divisorIndex = 0;
_generateTokenRandomness(id);
_safeMint(recipient, id);
_initPalette(id, recipient);
unchecked {
++i;
}
}
unchecked {
_warpsData.minted += uint32(mintLimit);
}
emit TokensMinted(recipient, startTokenId, mintLimit);
}
function freeMint(address recipient) external whenNotPaused {
require(address(paymentToken) != address(0), "Payment token not set");
require(recipient != address(0), "Invalid recipient");
require(!hasUsedFreeMint[msg.sender], "Free mint already used");
hasUsedFreeMint[msg.sender] = true;
emit FreeMintUsed(msg.sender);
uint256 startTokenId = tokenMintId;
for (uint256 i; i < mintLimit;) {
uint256 id = tokenMintId++;
StoredWarp storage warp = _warpsData.all[id];
warp.seed = uint16(id);
warp.divisorIndex = 0;
_generateTokenRandomness(id);
_safeMint(recipient, id);
_initPalette(id, recipient);
unchecked {
++i;
}
}
unchecked {
_warpsData.minted += uint32(mintLimit);
}
emit TokensMinted(recipient, startTokenId, mintLimit);
}
function composite(uint256 tokenId, uint256 burnId) external whenNotPaused {
_composite(tokenId, burnId);
unchecked {
++_warpsData.burned;
}
emit TokensComposited(tokenId, burnId);
}
function burn(uint256 tokenId) external whenNotPaused {
if (!_isApprovedOrOwner(msg.sender, tokenId)) {
revert NotAllowed();
}
_burn(tokenId);
unchecked {
++_warpsData.burned;
}
emit TokenBurned(tokenId, msg.sender);
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
_requireMinted(tokenId);
IWarps.Warp memory warp = WarpsArt.getWarp(tokenId, _warpsData);
Palette storage palStore = _palette[tokenId];
uint24[] memory pal = new uint24[](palStore.len);
for (uint8 i; i < palStore.len; ++i) {
pal[i] = palStore.colors[i];
}
bytes memory staticSvg = pal.length > 0
? WarpsArt.generateSVGWithPalette(warp, _warpsData, pal)
: WarpsArt.generateSVG(warp, _warpsData);
bytes memory metadata = abi.encodePacked(
"{",
'"name": "Warps ',
Utilities.uint2str(tokenId),
'",',
'"description": "Up and to the right.",',
'"image": ',
'"data:image/svg+xml;base64,',
Base64.encode(staticSvg),
'",',
'"attributes": [',
WarpsMetadata.attributes(warp),
"]",
"}"
);
return string(abi.encodePacked("data:application/json;base64,", Base64.encode(metadata)));
}
function _getWarpWithSeed(uint256 tokenId) internal view returns (IWarps.Warp memory) {
IWarps.Warp memory warp = WarpsArt.getWarp(tokenId, _warpsData);
if (_tokenMetadata[tokenId].seed != 0) {
warp.seed = _tokenMetadata[tokenId].seed;
}
return warp;
}
function _composite(uint256 tokenId, uint256 burnId) internal {
(StoredWarp storage toKeep,, uint8 divisorIndex) = _tokenOperation(tokenId, burnId);
uint8 nextDivisor = divisorIndex + 1;
uint8 gradient = 0;
uint8 colorBand = 0;
if (divisorIndex < 5) {
(gradient, colorBand) = _compositeGenes(tokenId, burnId);
toKeep.colorBands[divisorIndex] = colorBand;
toKeep.gradients[divisorIndex] = gradient;
}
_updatePaletteOnComposite(tokenId, burnId, divisorIndex);
toKeep.composites[divisorIndex] = uint16(burnId);
toKeep.divisorIndex = nextDivisor;
uint256 newSeed = uint256(
keccak256(
abi.encodePacked(
_tokenMetadata[tokenId].seed,
_tokenMetadata[burnId].seed,
gradient,
colorBand
)
)
) % type(uint128).max;
_tokenMetadata[tokenId].seed = newSeed;
_burn(burnId);
emit Composite(tokenId, burnId, WarpsArt.divisors()[toKeep.divisorIndex]);
emit MetadataUpdate(tokenId);
}
function _compositeGenes(uint256 tokenId, uint256 burnId) internal view returns (uint8 gradient, uint8 colorBand) {
Warp memory keeper = _getWarpWithSeed(tokenId);
Warp memory burner = _getWarpWithSeed(burnId);
uint256 randomizer = uint256(keccak256(abi.encodePacked(keeper.seed, burner.seed)));
gradient = Utilities.random(randomizer, 100) > 80
? randomizer % 2 == 0
? Utilities.minGt0(keeper.gradient, burner.gradient)
: Utilities.max(keeper.gradient, burner.gradient)
: Utilities.min(keeper.gradient, burner.gradient);
colorBand = Utilities.avg(keeper.colorBand, burner.colorBand);
}
function _tokenOperation(uint256 tokenId, uint256 burnId)
internal
view
returns (StoredWarp storage toKeep, StoredWarp storage toBurn, uint8 divisorIndex)
{
toKeep = _warpsData.all[tokenId];
toBurn = _warpsData.all[burnId];
divisorIndex = toKeep.divisorIndex;
require(
_isApprovedOrOwner(msg.sender, tokenId) && _isApprovedOrOwner(msg.sender, burnId)
&& divisorIndex == toBurn.divisorIndex && tokenId != burnId && divisorIndex <= MAX_COMPOSITE_LEVEL,
"Invalid composite operation"
);
}
function emergencyWithdraw() external onlyOwner {
require(address(paymentToken) != address(0), "Payment token not set");
uint256 balance = paymentToken.balanceOf(address(this));
require(balance > 0, "No funds to withdraw");
bool success = paymentToken.transfer(owner(), balance);
require(success, "ERC20 transfer failed");
prizePool.totalDeposited = 0;
prizePool.actualAvailable = 0;
emit EmergencyWithdrawn(balance);
emit PrizePoolUpdated(0);
}
function getAvailablePrizePool() public view returns (uint256) {
if (address(paymentToken) == address(0)) {
return 0;
}
return paymentToken.balanceOf(address(this));
}
function isWinningToken(uint256 tokenId) public view returns (bool) {
if (!_exists(tokenId)) return false;
Warp memory warp = _getWarpWithSeed(tokenId);
if (warp.warpsCount != 1) return false;
Palette storage p = _palette[tokenId];
if (p.len == 0) return false;
return p.colors[0] == _warpColorCode(winningColorIndex);
}
function getCurrentWinningColor() public view returns (string memory) {
return WarpColors.colors()[winningColorIndex];
}
function getColorFromIndex(uint8 _index) public pure returns (string memory) {
return WarpColors.getColorByIndex(_index);
}
function getIndexFromColor(string memory _color) public pure returns (uint8) {
return WarpColors.getIndexByColor(_color);
}
function updateWinningColorIndex(uint8 newIndex) external onlyOwner {
require(newIndex < 5, "Index must be < 5");
winningColorIndex = newIndex;
emit WinningColorIndexUpdated(newIndex);
}
function setWinningColor(string memory colorHex) external onlyOwner {
uint8 colorIndex = WarpColors.getIndexByColor(colorHex);
winningColorIndex = colorIndex;
emit WinningColorSet(colorHex, colorIndex);
emit WinningColorIndexUpdated(colorIndex);
}
function claimPrize(uint256 tokenId) external whenNotPaused {
require(_isApprovedOrOwner(msg.sender, tokenId), "Not token owner");
require(isWinningToken(tokenId), "Not a winning token");
require(address(paymentToken) != address(0), "Payment token not set");
require(prizePool.totalDeposited > 0, "Prize pool empty");
require(prizePool.actualAvailable > 0, "Actual prize pool is empty");
uint256 contractBalance = paymentToken.balanceOf(address(this));
require(contractBalance > 0, "No tokens in contract");
uint256 claimAmount = (prizePool.totalDeposited * winnerClaimPercentage) / 100;
if (claimAmount > prizePool.actualAvailable) {
claimAmount = prizePool.actualAvailable;
}
require(contractBalance >= claimAmount, "Insufficient tokens for prize claim");
prizePool.lastWinnerClaim = uint32(block.timestamp);
prizePool.totalDeposited -= claimAmount;
prizePool.actualAvailable -= claimAmount;
_burn(tokenId);
unchecked {
++_warpsData.burned;
}
bool success = paymentToken.transfer(msg.sender, claimAmount);
require(success, "ERC20 transfer failed");
uint8 oldColorIndex = winningColorIndex;
uint8 newColorIndex;
do {
uint256 randomSeed = uint256(
keccak256(
abi.encodePacked(block.timestamp, block.prevrandao, msg.sender, tokenId, prizePool.lastWinnerClaim)
)
);
newColorIndex = uint8(randomSeed % 5);
} while (newColorIndex == oldColorIndex);
winningColorIndex = newColorIndex;
emit PrizeClaimed(tokenId, msg.sender, claimAmount);
emit TokenBurned(tokenId, msg.sender);
emit PrizePoolUpdated(prizePool.totalDeposited);
emit WinningColorIndexUpdated(newColorIndex);
emit WinningColorSet(WarpColors.getColorByIndex(newColorIndex), newColorIndex);
}
function _initPalette(uint256 tokenId, address minter) internal {
Palette storage p = _palette[tokenId];
if (p.len != 0) return;
p.len = 3;
uint256 s = uint256(keccak256(abi.encodePacked(block.prevrandao, tokenId, minter)));
p.colors[0] = _warpColorCode(uint8(s & 0xFF) % 5);
p.colors[1] = _warpColorCode(uint8((s >> 8) & 0xFF) % 5);
p.colors[2] = _warpColorCode(uint8((s >> 16) & 0xFF) % 5);
}
function _warpColorCode(uint8 index) internal pure returns (uint24) {
if (index == 0) return 0xFF007A;
if (index == 1) return 0x855DCD;
if (index == 2) return 0xFF9900;
if (index == 3) return 0x52b043;
if (index == 4) return 0x1da1f2;
revert("Index out of bounds");
}
function _updatePaletteOnComposite(uint256 keepId, uint256 burnId, uint8 divisorIdx) internal {
Palette storage a = _palette[keepId];
Palette storage b = _palette[burnId];
uint256 r = uint256(keccak256(abi.encodePacked(a.colors[0], b.colors[0], block.prevrandao)));
if (divisorIdx == 0 && a.len == 3 && b.len == 3) {
a.colors[0] = a.colors[uint8(r) % 3];
a.colors[1] = b.colors[uint8(r >> 8) % 3];
a.colors[2] = 0;
a.len = 2;
} else if (divisorIdx == 1 && a.len == 2 && b.len == 2) {
a.colors[0] = (r & 1) == 0 ? a.colors[uint8(r) % 2] : b.colors[uint8(r >> 8) % 2];
a.colors[1] = 0;
a.len = 1;
}
}
function tokenColors(uint256 id) external view returns (uint24[] memory) {
Palette storage p = _palette[id];
uint24[] memory out = new uint24[](p.len);
for (uint8 i; i < p.len; ++i) {
out[i] = p.colors[i];
}
return out;
}
}
文件 22 的 23:WarpsArt.sol
pragma solidity ^0.8.17;
import "../interfaces/IWarps.sol";
import "./WarpColors.sol";
import "./Utilities.sol";
library WarpsArt {
function divisors() public pure returns (uint8[8] memory) {
return [20, 4, 1, 0, 0, 0, 0, 0];
}
function colorBands() public pure returns (uint8[7] memory) {
return [10, 8, 6, 4, 2, 1, 0];
}
function gradients() public pure returns (uint8[7] memory) {
return [0, 1, 2, 5, 8, 9, 10];
}
function getWarp(uint256 tokenId, IWarps.Warps storage warps) public view returns (IWarps.Warp memory warp) {
IWarps.StoredWarp memory stored = warps.all[tokenId];
return getWarp(tokenId, stored.divisorIndex, warps);
}
function getWarp(uint256 tokenId, uint8 divisorIndex, IWarps.Warps storage warps)
public
view
returns (IWarps.Warp memory warp)
{
IWarps.StoredWarp memory stored = warps.all[tokenId];
stored.divisorIndex = divisorIndex;
warp.stored = stored;
warp.seed = stored.seed;
warp.isRoot = divisorIndex == 0;
warp.hasManyWarps = divisorIndex < 6;
warp.composite = !warp.isRoot && divisorIndex < 7 ? stored.composites[divisorIndex - 1] : 0;
warp.colorBand = colorBandIndex(warp, divisorIndex);
warp.gradient = gradientIndex(warp, divisorIndex);
warp.warpsCount = divisors()[divisorIndex];
}
function gradientIndex(IWarps.Warp memory warp, uint8 divisorIndex) public pure returns (uint8) {
uint256 n = Utilities.random(warp.seed, "gradient", 100);
return divisorIndex == 0
? n < 20 ? uint8(1 + (n % 6)) : 0
: divisorIndex < 6 ? warp.stored.gradients[divisorIndex - 1] : 0;
}
function colorBandIndex(IWarps.Warp memory warp, uint8 divisorIndex) public pure returns (uint8) {
uint256 n = Utilities.random(warp.seed, "band", 10);
return divisorIndex == 0
? (n > 5 ? 2 : 3)
: divisorIndex < 6 ? warp.stored.colorBands[divisorIndex - 1] : 4;
}
function colorIndexes(uint8 divisorIndex, IWarps.Warp memory warp, IWarps.Warps storage warps)
public
view
returns (uint256[] memory)
{
uint8[8] memory divisors_ = divisors();
uint256 warpsCount = divisors_[divisorIndex];
uint256 seed = warp.seed;
uint8 colorBand = colorBands()[colorBandIndex(warp, divisorIndex)];
uint8 gradient = gradients()[gradientIndex(warp, divisorIndex)];
uint256 possibleColorChoices = divisorIndex > 0 ? divisors_[divisorIndex - 1] * 2 : 5;
uint256[] memory indexes = new uint256[](warpsCount);
indexes[0] = Utilities.random(seed, possibleColorChoices);
if (warp.hasManyWarps) {
if (gradient > 0) {
for (uint256 i = 1; i < warpsCount;) {
indexes[i] = (indexes[0] + (i * gradient * colorBand / warpsCount) % colorBand) % 5;
unchecked {
++i;
}
}
} else if (divisorIndex == 0) {
for (uint256 i = 1; i < warpsCount;) {
indexes[i] = (indexes[0] + Utilities.random(seed + i, colorBand)) % 5;
unchecked {
++i;
}
}
} else {
for (uint256 i = 1; i < warpsCount;) {
indexes[i] = Utilities.random(seed + i, possibleColorChoices);
unchecked {
++i;
}
}
}
}
if (divisorIndex > 0) {
uint8 previousDivisor = divisorIndex - 1;
uint256[] memory parentIndexes = colorIndexes(previousDivisor, warp, warps);
IWarps.Warp memory composited = getWarp(warp.composite, previousDivisor, warps);
uint256[] memory compositedIndexes = colorIndexes(previousDivisor, composited, warps);
uint8 count = divisors_[previousDivisor];
uint256 initialBranchIndex = indexes[0] % count;
indexes[0] = indexes[0] < count ? parentIndexes[initialBranchIndex] : compositedIndexes[initialBranchIndex];
if (gradient == 0) {
for (uint256 i; i < warpsCount;) {
uint256 branchIndex = indexes[i] % count;
indexes[i] = indexes[i] < count ? parentIndexes[branchIndex] : compositedIndexes[branchIndex];
unchecked {
++i;
}
}
} else {
for (uint256 i = 1; i < warpsCount;) {
indexes[i] = (indexes[0] + (i * gradient * colorBand / warpsCount) % colorBand) % 5;
unchecked {
++i;
}
}
}
}
return indexes;
}
function colors(IWarps.Warp memory warp, IWarps.Warps storage warps)
public
view
returns (string[] memory, uint256[] memory)
{
if (warp.stored.divisorIndex == 7) {
string[] memory zeroColors = new string[](1);
uint256[] memory zeroIndexes = new uint256[](1);
zeroColors[0] = "000";
zeroIndexes[0] = 999;
return (zeroColors, zeroIndexes);
}
uint256[] memory indexes = colorIndexes(warp.stored.divisorIndex, warp, warps);
string[] memory warpColors = new string[](indexes.length);
string[5] memory allColors = WarpColors.colors();
warpColors[0] = allColors[indexes[0]];
for (uint256 i = 1; i < indexes.length; i++) {
warpColors[i] = allColors[indexes[i]];
}
return (warpColors, indexes);
}
function perRow(uint8 warps) public pure returns (uint8) {
return warps == 80 ? 8 : warps >= 20 ? 4 : warps == 10 || warps == 4 ? 2 : 1;
}
function rowX(uint8 warps) public pure returns (uint16) {
if (warps == 2) {
return 310;
}
return warps <= 1 ? 286 : warps == 5 ? 304 : warps == 10 || warps == 4 ? 268 : 196;
}
function rowY(uint8 warps) public pure returns (uint16) {
if (warps == 2) {
return 270;
}
return warps > 4 ? 160 : warps == 4 ? 268 : warps > 1 ? 304 : 286;
}
function generateWarps(WarpRenderData memory data) public pure returns (bytes memory) {
bytes memory warpsBytes;
uint8 warpsCount = data.count;
for (uint8 i; i < warpsCount; i++) {
data.indexInRow = i % data.perRow;
data.isNewRow = data.indexInRow == 0 && i > 0;
if (data.isNewRow) data.rowY += data.spaceY;
if (data.isNewRow && data.indent) {
if (i == 0) {
data.rowX += data.spaceX / 2;
}
if (i % (data.perRow * 2) == 0) {
data.rowX -= data.spaceX / 2;
} else {
data.rowX += data.spaceX / 2;
}
}
string memory translateX = Utilities.uint2str(data.rowX + data.indexInRow * data.spaceX);
string memory translateY = Utilities.uint2str(data.rowY);
string memory color = data.colors[i];
warpsBytes = abi.encodePacked(
warpsBytes,
abi.encodePacked(
'<g transform="translate(',
translateX,
", ",
translateY,
')">',
'<g transform="translate(3, 3) scale(',
data.scale,
')">',
'<path d="M15 26.264c1.271 0 4.012 4.144 5.207 3.703 1.194-.441.668-5.403 1.643-6.233.974-.83 5.698.558 6.334-.56.636-1.117-2.91-4.576-2.69-5.847.221-1.27 4.72-3.29 4.498-4.56-.22-1.271-5.127-1.607-5.763-2.725-.636-1.117 1.53-5.597.556-6.427-.974-.83-4.945 2.114-6.14 1.672C17.45 4.846 16.272 0 15 0c-1.272 0-2.45 4.846-3.645 5.287-1.195.442-5.166-2.502-6.14-1.672-.974.83 1.192 5.31.556 6.427C5.136 11.16.23 11.496.008 12.767c-.22 1.27 4.277 3.29 4.497 4.56.221 1.271-3.325 4.73-2.689 5.847.636 1.118 5.36-.27 6.334.56.974.83.448 5.791 1.643 6.233 1.196.441 3.936-3.703 5.207-3.703Z" fill="#',
color,
'"/>',
'<path d="M14.999 24.216c1.04 0 3.283 3.39 4.26 3.03.978-.361.547-4.421 1.345-5.1.797-.679 4.662.456 5.182-.458.52-.915-2.381-3.744-2.2-4.784.18-1.04 3.86-2.691 3.68-3.731-.181-1.04-4.196-1.315-4.716-2.23-.52-.913 1.253-4.58.456-5.258-.797-.679-4.047 1.73-5.025 1.368-.977-.361-1.941-4.326-2.982-4.326-1.04 0-2.004 3.965-2.982 4.326-.977.361-4.227-2.047-5.024-1.368-.797.678.976 4.345.456 5.259-.52.914-4.535 1.19-4.716 2.229-.18 1.04 3.5 2.691 3.68 3.731.18 1.04-2.72 3.87-2.2 4.784.52.914 4.385-.22 5.182.458.797.678.367 4.738 1.344 5.1.978.36 3.22-3.03 4.26-3.03Z" fill="#000"/>',
'<path d="M14.998 22.168c.81 0 2.553 2.637 3.314 2.357.76-.281.425-3.44 1.046-3.967.62-.528 3.625.355 4.03-.356.405-.712-1.852-2.912-1.711-3.72.14-.81 3.003-2.094 2.862-2.903-.14-.809-3.263-1.023-3.668-1.734-.404-.711.975-3.562.355-4.09S18.078 9.1 17.318 8.819c-.76-.28-1.51-3.364-2.32-3.364-.809 0-1.558 3.083-2.319 3.364-.76.281-3.288-1.592-3.907-1.064-.62.528.758 3.379.354 4.09-.405.711-3.527.925-3.668 1.734-.14.809 2.722 2.093 2.862 2.902.14.809-2.116 3.01-1.711 3.72.404.712 3.41-.171 4.03.357.62.528.286 3.685 1.046 3.966.76.281 2.505-2.356 3.314-2.356Z" fill="#',
color,
'"/>',
'<path d="M15.005 20.12c.579 0 1.824 1.884 2.367 1.683.543-.2.304-2.456.747-2.833.443-.377 2.59.254 2.88-.255.288-.508-1.323-2.08-1.223-2.657.1-.578 2.145-1.495 2.044-2.073-.1-.578-2.33-.73-2.62-1.238-.288-.508.696-2.545.254-2.922-.443-.377-2.248.96-2.792.76-.543-.2-1.078-2.403-1.656-2.403-.578 0-1.114 2.202-1.657 2.403-.543.2-2.348-1.137-2.791-.76-.443.377.542 2.414.253 2.922-.29.508-2.52.66-2.62 1.238-.1.578 1.944 1.495 2.044 2.073.1.578-1.511 2.15-1.222 2.657.289.509 2.437-.122 2.88.255.442.377.203 2.632.746 2.833.543.2 1.789-1.683 2.367-1.683Z" fill="#000"/>',
'<path d="M15 18.584c.404 0 1.276 1.319 1.656 1.178.38-.14.213-1.719.523-1.983.31-.264 1.813.177 2.015-.178.202-.356-.926-1.456-.855-1.86.07-.405 1.5-1.047 1.43-1.451-.07-.405-1.63-.512-1.833-.867-.203-.356.487-1.782.177-2.046-.31-.264-1.574.673-1.954.532-.38-.14-.755-1.682-1.16-1.682-.404 0-.78 1.542-1.16 1.682-.38.141-1.643-.796-1.953-.532-.31.264.38 1.69.177 2.046-.202.355-1.764.462-1.834.867-.07.404 1.36 1.046 1.431 1.45.07.405-1.058 1.505-.856 1.86.203.356 1.706-.085 2.016.179.31.264.142 1.843.523 1.983.38.14 1.252-1.178 1.656-1.178Z" fill="#',
color,
'"/>',
"</g>",
"</g>"
)
);
}
return warpsBytes;
}
function collectRenderData(IWarps.Warp memory warp, IWarps.Warps storage warps)
public
view
returns (WarpRenderData memory data)
{
data.warp = warp;
data.isBlack = warp.stored.divisorIndex == 7;
data.count = data.isBlack ? 1 : divisors()[warp.stored.divisorIndex];
(string[] memory colors_, uint256[] memory colorIndexes_) = colors(warp, warps);
data.gridColor = "#000000";
data.canvasColor = "#000000";
data.colorIndexes = colorIndexes_;
data.colors = colors_;
data.scale = data.count > 20 ? "1.2" : data.count > 1 ? "2" : "3";
data.spaceX = data.count == 80 ? 36 : 72;
data.spaceY = data.count > 20 ? 36 : 72;
data.perRow = perRow(data.count);
data.indent = data.count == 40;
data.rowX = rowX(data.count);
data.rowY = rowY(data.count);
}
function generateGridRow() public pure returns (bytes memory) {
bytes memory row;
for (uint256 i; i < 8; i++) {
row = abi.encodePacked(row, '<use href="#square" x="', Utilities.uint2str(196 + i * 36), '" y="160"/>');
}
return row;
}
function generateGrid() public pure returns (bytes memory) {
bytes memory grid;
for (uint256 i; i < 10; i++) {
grid = abi.encodePacked(grid, '<use href="#row" y="', Utilities.uint2str(i * 36), '"/>');
}
return abi.encodePacked('<g id="grid" x="196" y="160">', grid, "</g>");
}
function generateSVG(IWarps.Warp memory warp, IWarps.Warps storage warps) public view returns (bytes memory) {
WarpRenderData memory data = collectRenderData(warp, warps);
return abi.encodePacked(
"<svg ",
'viewBox="0 0 680 680" ',
'fill="none" xmlns="http://www.w3.org/2000/svg" ',
'style="width:100%;background:black;"',
">",
"<defs>",
'<rect id="square" width="36" height="36" stroke="',
data.gridColor,
'"></rect>',
'<g id="row">',
generateGridRow(),
"</g>" "</defs>",
'<rect width="680" height="680" fill="black"/>',
'<rect x="188" y="152" width="304" height="376" fill="',
data.canvasColor,
'"/>',
generateGrid(),
generateWarps(data),
"</svg>"
);
}
function _uint24ToHex(uint24 value) internal pure returns (string memory) {
bytes16 symbols = "0123456789abcdef";
bytes memory buffer = new bytes(6);
for (uint256 i; i < 6; ++i) {
buffer[5 - i] = symbols[value & 0xF];
value >>= 4;
}
return string(buffer);
}
function generateSVGWithPalette(IWarps.Warp memory warp, IWarps.Warps storage warps, uint24[] memory palette)
public
view
returns (bytes memory)
{
WarpRenderData memory data = collectRenderData(warp, warps);
uint256 len = data.count;
string[] memory custom = new string[](len);
for (uint256 i; i < len; ++i) {
custom[i] = _uint24ToHex(palette[i % palette.length]);
}
data.colors = custom;
return abi.encodePacked(
"<svg ",
'viewBox="0 0 680 680" ',
'fill="none" xmlns="http://www.w3.org/2000/svg" ',
'style="width:100%;background:black;"',
">",
"<defs>",
'<rect id="square" width="36" height="36" stroke="',
data.gridColor,
'"></rect>',
'<g id="row">',
generateGridRow(),
"</g>" "</defs>",
'<rect width="680" height="680" fill="black"/>',
'<rect x="188" y="152" width="304" height="376" fill="',
data.canvasColor,
'"/>',
generateGrid(),
generateWarps(data),
"</svg>"
);
}
}
struct WarpRenderData {
IWarps.Warp warp;
uint256[] colorIndexes;
string[] colors;
string canvasColor;
string gridColor;
string duration;
string scale;
uint32 seed;
uint16 rowX;
uint16 rowY;
uint8 count;
uint8 spaceX;
uint8 spaceY;
uint8 perRow;
uint8 indexInRow;
uint8 isIndented;
bool isNewRow;
bool isBlack;
bool indent;
bool isStatic;
}
文件 23 的 23:WarpsMetadata.sol
pragma solidity ^0.8.17;
import "lib/openzeppelin-contracts/contracts/utils/Base64.sol";
import "./WarpsArt.sol";
import "../interfaces/IWarps.sol";
import "./Utilities.sol";
library WarpsMetadata {
function tokenURI(uint256 tokenId, IWarps.Warps storage warps) public view returns (string memory) {
IWarps.Warp memory warp = WarpsArt.getWarp(tokenId, warps);
bytes memory staticSvg = WarpsArt.generateSVG(warp, warps);
bytes memory metadata = abi.encodePacked(
"{",
'"name": "Warps ',
Utilities.uint2str(tokenId),
'",',
'"description": "Up and to the right.",',
'"image": ',
'"data:image/svg+xml;base64,',
Base64.encode(staticSvg),
'",',
'"attributes": [',
attributes(warp),
"]",
"}"
);
return string(abi.encodePacked("data:application/json;base64,", Base64.encode(metadata)));
}
function attributes(IWarps.Warp memory warp) public pure returns (bytes memory) {
bool showVisualAttributes = warp.hasManyWarps;
return abi.encodePacked(
showVisualAttributes
? trait("Color Band", colorBand(WarpsArt.colorBandIndex(warp, warp.stored.divisorIndex)), ",")
: "",
showVisualAttributes
? trait("Gradient", gradients(WarpsArt.gradientIndex(warp, warp.stored.divisorIndex)), ",")
: "",
trait("Warps", Utilities.uint2str(warp.warpsCount), "")
);
}
function gradients(uint8 gradientIndex) public pure returns (string memory) {
return ["None", "Linear", "Double Linear", "Reflected", "Double Angled", "Angled", "Linear Z"][gradientIndex];
}
function colorBand(uint8 bandIndex) public pure returns (string memory) {
return ["Eighty", "Sixty", "Forty", "Twenty", "Ten", "Five", "One"][bandIndex];
}
function trait(string memory traitType, string memory traitValue, string memory append)
public
pure
returns (string memory)
{
return
string(abi.encodePacked("{", '"trait_type": "', traitType, '",' '"value": "', traitValue, '"' "}", append));
}
function generateHTML(uint256 tokenId, bytes memory svg) public pure returns (bytes memory) {
return abi.encodePacked(
"<!DOCTYPE html>",
'<html lang="en">',
"<head>",
'<meta charset="UTF-8">',
'<meta http-equiv="X-UA-Compatible" content="IE=edge">',
'<meta name="viewport" content="width=device-width, initial-scale=1.0">',
"<title>Warp #",
Utilities.uint2str(tokenId),
"</title>",
"<style>",
"html,",
"body {",
"margin: 0;",
"background: #EFEFEF;",
"overflow: hidden;",
"}",
"svg {",
"max-width: 100vw;",
"max-height: 100vh;",
"}",
"</style>",
"</head>",
"<body>",
svg,
"</body>",
"</html>"
);
}
}
{
"compilationTarget": {
"src/Warps.sol": "Warps"
},
"evmVersion": "shanghai",
"libraries": {
"src/libraries/WarpColors.sol:WarpColors": "0xb3b22aaa28badc8b954add722e0da56fff329530",
"src/libraries/WarpsArt.sol:WarpsArt": "0x717073089d146665f68188a7096c2efd41143889",
"src/libraries/WarpsMetadata.sol:WarpsMetadata": "0x6b217d26f7c319be29d393825bc90563a608839a"
},
"metadata": {
"appendCBOR": false,
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 99999999
},
"remappings": [
":ds-test/=lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
":openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":solady-test/=lib/solady/test/",
":solady/=lib/solady/src/",
":uniswap-v2-core/=lib/uniswap/v2-core/contracts/",
":uniswap-v3-core/=lib/uniswap/v3-core/contracts/",
":uniswap-v3-periphery/=lib/uniswap/v3-periphery/contracts/",
":uniswap-v4-core/=lib/uniswap/v4-core/src/",
":uniswap-v4-periphery/=lib/uniswap/v4-periphery/src/",
":uniswap/=lib/uniswap/"
],
"viaIR": true
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BlackWarp__InvalidWarp","type":"error"},{"inputs":[],"name":"ERC721__InvalidApproval","type":"error"},{"inputs":[],"name":"ERC721__InvalidOwner","type":"error"},{"inputs":[],"name":"ERC721__InvalidToken","type":"error"},{"inputs":[],"name":"ERC721__NotAllowed","type":"error"},{"inputs":[],"name":"ERC721__TokenExists","type":"error"},{"inputs":[],"name":"ERC721__TransferToNonReceiver","type":"error"},{"inputs":[],"name":"ERC721__TransferToZero","type":"error"},{"inputs":[],"name":"InvalidTokenCount","type":"error"},{"inputs":[],"name":"NotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"burnedId","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"warps","type":"uint8"}],"name":"Composite","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pauser","type":"address"}],"name":"ContractPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"unpauser","type":"address"}],"name":"ContractUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"FreeMintUsed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"newLimit","type":"uint8"}],"name":"MintLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"MintPriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"newPercentage","type":"uint8"}],"name":"OwnerMintSharePercentageUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintPrice","type":"uint256"}],"name":"PaymentTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PrizeClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"totalDeposited","type":"uint256"}],"name":"PrizePoolUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"burnedId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Sacrifice","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"burner","type":"address"}],"name":"TokenBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keptTokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"burnedTokenId","type":"uint256"}],"name":"TokensComposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"startTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"}],"name":"TokensMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"newPercentage","type":"uint8"}],"name":"WinnerClaimPercentageUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"newIndex","type":"uint8"}],"name":"WinningColorIndexUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"colorHex","type":"string"},{"indexed":false,"internalType":"uint8","name":"colorIndex","type":"uint8"}],"name":"WinningColorSet","type":"event"},{"inputs":[],"name":"MAX_COMPOSITE_LEVEL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"claimPrize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"burnId","type":"uint256"}],"name":"composite","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"freeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getActualAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"getAvailablePrizePool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_index","type":"uint8"}],"name":"getColorFromIndex","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getCurrentWinningColor","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_color","type":"string"}],"name":"getIndexFromColor","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTotalDeposited","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hasUsedFreeMint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isWinningToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintLimit","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownerMintSharePercentage","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paymentToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prizePool","outputs":[{"internalType":"uint32","name":"lastWinnerClaim","type":"uint32"},{"internalType":"uint256","name":"totalDeposited","type":"uint256"},{"internalType":"uint256","name":"actualAvailable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","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":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_mintPrice","type":"uint256"}],"name":"setPaymentToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"colorHex","type":"string"}],"name":"setWinningColor","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":"id","type":"uint256"}],"name":"tokenColors","outputs":[{"internalType":"uint24[]","name":"","type":"uint24[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenMintId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"newLimit","type":"uint8"}],"name":"updateMintLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"updateMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"newPercentage","type":"uint8"}],"name":"updateOwnerMintSharePercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"newPercentage","type":"uint8"}],"name":"updateWinnerClaimPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"newIndex","type":"uint8"}],"name":"updateWinningColorIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"winnerClaimPercentage","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"winningColorIndex","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"}]