编译器
0.8.26+commit.8a97fa7a
文件 1 的 45: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 的 45:AutomaticValidatorTransferApproval.sol
pragma solidity ^0.8.4;
import "../access/OwnablePermissions.sol";
abstract contract AutomaticValidatorTransferApproval is OwnablePermissions {
event AutomaticApprovalOfTransferValidatorSet(bool autoApproved);
bool public autoApproveTransfersFromValidator;
function setAutomaticApprovalOfTransfersFromValidator(bool autoApprove) external {
_requireCallerIsContractOwner();
autoApproveTransfersFromValidator = autoApprove;
emit AutomaticApprovalOfTransferValidatorSet(autoApprove);
}
}
文件 3 的 45:BasicRoyalties.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/common/ERC2981.sol";
abstract contract BasicRoyaltiesBase is ERC2981 {
event DefaultRoyaltySet(address indexed receiver, uint96 feeNumerator);
event TokenRoyaltySet(uint256 indexed tokenId, address indexed receiver, uint96 feeNumerator);
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual override {
super._setDefaultRoyalty(receiver, feeNumerator);
emit DefaultRoyaltySet(receiver, feeNumerator);
}
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual override {
super._setTokenRoyalty(tokenId, receiver, feeNumerator);
emit TokenRoyaltySet(tokenId, receiver, feeNumerator);
}
}
abstract contract BasicRoyalties is BasicRoyaltiesBase {
constructor(address receiver, uint96 feeNumerator) {
_setDefaultRoyalty(receiver, feeNumerator);
}
}
abstract contract BasicRoyaltiesInitializable is BasicRoyaltiesBase {}
文件 4 的 45:BioCanvas.sol
pragma solidity ^0.8.0;
import "@limitbreak/creator-token-standards/src/access/OwnableBasic.sol";
import "@limitbreak/creator-token-standards/src/erc1155c/ERC1155C.sol";
import "@limitbreak/creator-token-standards/src/programmable-royalties/BasicRoyalties.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./Drifter.sol";
contract BioCanvas is ERC1155C, BasicRoyalties, OwnableBasic {
using Strings for uint256;
uint96 public constant ROYALTY_FEE_NUMERATOR = 500;
uint256 public minted;
string public baseURI = "https://m.cyberbrokers.com/base/biocanvas/";
address public DRIFTER_ADDRESS;
address[] public BIO_CANVAS_MINTER_ADDRESSES;
modifier onlyBioCanvasMinters() {
bool isMinter = false;
for (uint256 i = 0; i < BIO_CANVAS_MINTER_ADDRESSES.length; i++) {
if (BIO_CANVAS_MINTER_ADDRESSES[i] == msg.sender) {
isMinter = true;
break;
}
}
require(isMinter, "Caller is not a BioCanvas minter");
_;
}
modifier onlyDrifterAddress() {
require(msg.sender == DRIFTER_ADDRESS, "Caller is not the Drifter contract");
_;
}
function name() public pure returns (string memory) {
return "Drifter BioCanvases";
}
function symbol() public pure returns (string memory) {
return "DRIFTERBIOCANVAS";
}
constructor(string memory uri_, address _royaltyReceiver) ERC1155OpenZeppelin(uri_) BasicRoyalties(_royaltyReceiver, ROYALTY_FEE_NUMERATOR) OwnableBasic() {
baseURI = uri_;
}
function setBaseURI(string memory _baseURI) external onlyOwner {
baseURI = _baseURI;
}
function addBioCanvasMinter(address minterAddress) external onlyOwner {
require(minterAddress != address(0), "Invalid minter address");
for (uint256 i = 0; i < BIO_CANVAS_MINTER_ADDRESSES.length; i++) {
if (BIO_CANVAS_MINTER_ADDRESSES[i] == minterAddress) {
return;
}
}
BIO_CANVAS_MINTER_ADDRESSES.push(minterAddress);
}
function removeBioCanvasMinter(address minterAddress) external onlyOwner {
for (uint256 i = 0; i < BIO_CANVAS_MINTER_ADDRESSES.length; i++) {
if (BIO_CANVAS_MINTER_ADDRESSES[i] == minterAddress) {
BIO_CANVAS_MINTER_ADDRESSES[i] = BIO_CANVAS_MINTER_ADDRESSES[BIO_CANVAS_MINTER_ADDRESSES.length - 1];
BIO_CANVAS_MINTER_ADDRESSES.pop();
break;
}
}
}
function setDrifterAddress(address drifterAddress) external onlyOwner {
DRIFTER_ADDRESS = drifterAddress;
}
function mint(address to, uint256 tokenId, uint256 amount) external onlyBioCanvasMinters {
_mint(to, tokenId, amount, "");
minted += amount;
}
function convertToDrifter(uint256 id, uint256 value, address to) external onlyDrifterAddress returns (bool) {
require(balanceOf(to, id) >= value, "Caller does not own enough BioCanvas tokens");
_burn(to, id, value);
return true;
}
function totalSupply() public view returns (uint256) {
return minted;
}
function uri(uint256 tokenId) public view virtual override returns (string memory) {
return string(abi.encodePacked(baseURI, tokenId.toString()));
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155C, ERC2981) returns (bool) {
return super.supportsInterface(interfaceId);
}
function setDefaultRoyalty(address receiver, uint96 feeNumerator) external onlyOwner {
_setDefaultRoyalty(receiver, feeNumerator);
}
function setTokenRoyalty(address receiver, uint256 tokenId, uint96 feeNumerator) external onlyOwner {
_setTokenRoyalty(tokenId, receiver, feeNumerator);
}
receive() external payable {
revert("Direct ETH transfers not allowed");
}
}
文件 5 的 45:Constants.sol
pragma solidity ^0.8.4;
bytes32 constant ZERO_BYTES32 = bytes32(0);
uint256 constant ZERO = 0;
uint256 constant ONE = 1;
uint8 constant ORDER_STATE_OPEN = 0;
uint8 constant ORDER_STATE_FILLED = 1;
uint8 constant ORDER_STATE_CANCELLED = 2;
uint256 constant TOKEN_TYPE_ERC721 = 721;
uint256 constant TOKEN_TYPE_ERC1155 = 1155;
uint256 constant TOKEN_TYPE_ERC20 = 20;
bytes32 constant UPPER_BIT_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
bytes32 constant UPDATE_APPROVAL_TYPEHASH =
keccak256("UpdateApprovalBySignature(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 approvalExpiration,uint256 sigDeadline,uint256 masterNonce)");
bytes32 constant SINGLE_USE_PERMIT_TYPEHASH =
keccak256("PermitTransferFrom(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce)");
string constant SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB =
"PermitTransferFromWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce,";
string constant PERMIT_ORDER_ADVANCED_TYPEHASH_STUB =
"PermitOrderWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 salt,address operator,uint256 expiration,uint256 masterNonce,";
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC721 = 1 << 0;
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC1155 = 1 << 1;
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC20 = 1 << 2;
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721 = 1 << 3;
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155 = 1 << 4;
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20 = 1 << 5;
uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC1155 = 1 << 6;
uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC20 = 1 << 7;
文件 6 的 45: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;
}
}
文件 7 的 45:CreatorTokenBase.sol
pragma solidity ^0.8.4;
import "../access/OwnablePermissions.sol";
import "../interfaces/ICreatorToken.sol";
import "../interfaces/ICreatorTokenLegacy.sol";
import "../interfaces/ITransferValidator.sol";
import "./TransferValidation.sol";
import "../interfaces/ITransferValidatorSetTokenType.sol";
abstract contract CreatorTokenBase is OwnablePermissions, TransferValidation, ICreatorToken {
error CreatorTokenBase__InvalidTransferValidatorContract();
address public constant DEFAULT_TRANSFER_VALIDATOR = address(0x721C002B0059009a671D00aD1700c9748146cd1B);
bool private isValidatorInitialized;
address private transferValidator;
constructor() {
_emitDefaultTransferValidator();
_registerTokenType(DEFAULT_TRANSFER_VALIDATOR);
}
function setTransferValidator(address transferValidator_) public {
_requireCallerIsContractOwner();
bool isValidTransferValidator = transferValidator_.code.length > 0;
if(transferValidator_ != address(0) && !isValidTransferValidator) {
revert CreatorTokenBase__InvalidTransferValidatorContract();
}
emit TransferValidatorUpdated(address(getTransferValidator()), transferValidator_);
isValidatorInitialized = true;
transferValidator = transferValidator_;
_registerTokenType(transferValidator_);
}
function getTransferValidator() public view override returns (address validator) {
validator = transferValidator;
if (validator == address(0)) {
if (!isValidatorInitialized) {
validator = DEFAULT_TRANSFER_VALIDATOR;
}
}
}
function _preValidateTransfer(
address caller,
address from,
address to,
uint256 tokenId,
uint256 ) internal virtual override {
address validator = getTransferValidator();
if (validator != address(0)) {
if (msg.sender == validator) {
return;
}
ITransferValidator(validator).validateTransfer(caller, from, to, tokenId);
}
}
function _preValidateTransfer(
address caller,
address from,
address to,
uint256 tokenId,
uint256 amount,
uint256 ) internal virtual override {
address validator = getTransferValidator();
if (validator != address(0)) {
if (msg.sender == validator) {
return;
}
ITransferValidator(validator).validateTransfer(caller, from, to, tokenId, amount);
}
}
function _tokenType() internal virtual pure returns(uint16);
function _registerTokenType(address validator) internal {
if (validator != address(0)) {
uint256 validatorCodeSize;
assembly {
validatorCodeSize := extcodesize(validator)
}
if(validatorCodeSize > 0) {
try ITransferValidatorSetTokenType(validator).setTokenTypeOfCollection(address(this), _tokenType()) {
} catch { }
}
}
}
function _emitDefaultTransferValidator() internal {
emit TransferValidatorUpdated(address(0), DEFAULT_TRANSFER_VALIDATOR);
}
}
文件 8 的 45:DNACard.sol
pragma solidity ^0.8.4;
import "@limitbreak/creator-token-standards/src/access/OwnableBasic.sol";
import "@limitbreak/creator-token-standards/src/erc721c/ERC721C.sol";
import "@limitbreak/creator-token-standards/src/programmable-royalties/BasicRoyalties.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./DNACardReveal.sol";
import "./DNACardLib.sol";
contract DNACard is OwnableBasic, ERC721C, BasicRoyalties {
using Address for address;
using Strings for uint256;
uint96 public constant ROYALTY_FEE_NUMERATOR = 500;
string public baseURI = "https://m.cyberbrokers.com/base/dnapack/";
mapping(uint256 => uint8) public cardSkins;
uint256 public constant SMALL_SUPPLY = 2707;
uint256 public constant MEDIUM_SUPPLY = 3907;
uint256 public constant LARGE_SUPPLY = 1163;
uint256 public smallMinted;
uint256 public mediumMinted;
uint256 public largeMinted;
uint256 public totalRevealed;
uint256[] public cardSkinSupplies = [0, 2707, 1303, 1303, 1303, 233, 233, 233, 233, 233];
address[] public DNA_CARD_MINTER_ADDRESSES;
DNACardReveal public dnaCardRevealContract;
mapping(uint256 => DNACardLib.CardSize) public cardSizes;
mapping(uint256 => address) public revealedOwners;
event DNACardRevealed(uint256 indexed tokenId, uint256[] gearIds);
event DNACardHarvested(uint256 indexed tokenId, uint256[] harvestedGearIds);
modifier onlyDnaCardMinters() {
bool isMinter = false;
for (uint256 i = 0; i < DNA_CARD_MINTER_ADDRESSES.length; i++) {
if (DNA_CARD_MINTER_ADDRESSES[i] == msg.sender) {
isMinter = true;
break;
}
}
require(isMinter, "Caller is not a DNA Card minter");
_;
}
constructor(
address royaltyReceiver_,
string memory name_,
string memory symbol_
) ERC721OpenZeppelin(name_, symbol_) BasicRoyalties(royaltyReceiver_, ROYALTY_FEE_NUMERATOR) {}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721C, ERC2981) returns (bool) {
return super.supportsInterface(interfaceId);
}
function addDnaCardMinter(address minterAddress) external onlyOwner {
require(minterAddress != address(0), "Invalid minter address");
for (uint256 i = 0; i < DNA_CARD_MINTER_ADDRESSES.length; i++) {
if (DNA_CARD_MINTER_ADDRESSES[i] == minterAddress) {
return;
}
}
DNA_CARD_MINTER_ADDRESSES.push(minterAddress);
}
function removeDnaCardMinter(address minterAddress) external onlyOwner {
for (uint256 i = 0; i < DNA_CARD_MINTER_ADDRESSES.length; i++) {
if (DNA_CARD_MINTER_ADDRESSES[i] == minterAddress) {
DNA_CARD_MINTER_ADDRESSES[i] = DNA_CARD_MINTER_ADDRESSES[DNA_CARD_MINTER_ADDRESSES.length - 1];
DNA_CARD_MINTER_ADDRESSES.pop();
break;
}
}
}
function setDnaCardRevealContract(address payable dnaCardRevealAddress) external onlyOwner {
require(dnaCardRevealAddress != address(0), "Invalid DNA Card Reveal contract address");
dnaCardRevealContract = DNACardReveal(dnaCardRevealAddress);
}
function reveal(uint256 tokenId) external {
require(address(dnaCardRevealContract) != address(0), "DNA Card Reveal contract not set");
require(_exists(tokenId), "Token does not exist");
require(_isApprovedOrOwner(_msgSender(), tokenId), "Caller is not owner nor approved");
require(revealedOwners[tokenId] == address(0), "Token already revealed");
revealedOwners[tokenId] = _msgSender();
uint256[] memory selectedGear = dnaCardRevealContract.reveal(_msgSender(), tokenId, getCardSize(tokenId), getCardSkin(tokenId));
_burn(tokenId);
totalRevealed++;
emit DNACardRevealed(tokenId, selectedGear);
}
function harvestReveal(uint256 tokenId, uint256[] calldata selectedGearIds) external {
require(address(dnaCardRevealContract) != address(0), "DNA Card Reveal contract not set");
require(revealedOwners[tokenId] != address(0), "DNA Card not revealed yet");
require(revealedOwners[tokenId] == _msgSender(), "Only revealed owner can harvest");
uint256[] memory harvestedGear = dnaCardRevealContract.harvestReveal(_msgSender(), tokenId, getCardSize(tokenId), selectedGearIds);
emit DNACardHarvested(tokenId, harvestedGear);
}
function getRevealedGear(uint256 tokenId) external view returns (uint256[] memory) {
require(address(dnaCardRevealContract) != address(0), "DNA Card Reveal contract not set");
return dnaCardRevealContract.getRevealedGear(tokenId);
}
function getRemainingSelectionTime(uint256 tokenId) external view returns (uint256) {
require(address(dnaCardRevealContract) != address(0), "DNA Card Reveal contract not set");
return dnaCardRevealContract.getRemainingSelectionTime(tokenId);
}
function isRevealed(uint256 tokenId) external view returns (bool) {
require(address(dnaCardRevealContract) != address(0), "DNA Card Reveal contract not set");
return dnaCardRevealContract.isRevealed(tokenId);
}
function isHarvested(uint256 tokenId) external view returns (bool) {
require(address(dnaCardRevealContract) != address(0), "DNA Card Reveal contract not set");
return dnaCardRevealContract.isHarvested(tokenId);
}
function SELECTION_TIME_LIMIT() external view returns (uint256) {
require(address(dnaCardRevealContract) != address(0), "DNA Card Reveal contract not set");
return dnaCardRevealContract.SELECTION_TIME_LIMIT();
}
function _selectCardSkin(DNACardLib.CardSize cardSize) internal view returns (uint8) {
if (cardSize == DNACardLib.CardSize.SMALL) {
require(cardSkinSupplies[1] > 0, "Small pack type depleted");
return 1;
} else if (cardSize == DNACardLib.CardSize.MEDIUM) {
uint256 totalRemaining = 0;
for (uint8 i = 2; i <= 4; i++) {
totalRemaining += cardSkinSupplies[i];
}
require(totalRemaining > 0, "Medium pack types depleted");
uint256 randomNum = uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, msg.sender))) % totalRemaining;
uint256 cumulative = 0;
for (uint8 i = 2; i <= 4; i++) {
cumulative += cardSkinSupplies[i];
if (randomNum < cumulative) {
return i;
}
}
return 4;
} else {
uint256 totalRemaining = 0;
for (uint8 i = 5; i <= 9; i++) {
totalRemaining += cardSkinSupplies[i];
}
require(totalRemaining > 0, "Large pack types depleted");
uint256 randomNum = uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, msg.sender))) % totalRemaining;
uint256 cumulative = 0;
for (uint8 i = 5; i <= 9; i++) {
cumulative += cardSkinSupplies[i];
if (randomNum < cumulative) {
return i;
}
}
return 9;
}
}
function mint(address to, uint8 cardSize) external onlyDnaCardMinters returns (uint256) {
require(cardSize >= 0 && cardSize <= 2, "Invalid card type");
uint8 cardSkin = _selectCardSkin(DNACardLib.CardSize(cardSize));
require(cardSkinSupplies[cardSkin] > 0, "Type supply depleted");
cardSkinSupplies[cardSkin]--;
uint256 tokenId;
if (cardSize == 0) {
require(smallMinted < SMALL_SUPPLY, "Small card supply exceeded");
smallMinted++;
tokenId = smallMinted;
} else if (cardSize == 1) {
require(mediumMinted < MEDIUM_SUPPLY, "Medium card supply exceeded");
mediumMinted++;
tokenId = SMALL_SUPPLY + mediumMinted;
} else {
require(largeMinted < LARGE_SUPPLY, "Large card supply exceeded");
largeMinted++;
tokenId = SMALL_SUPPLY + MEDIUM_SUPPLY + largeMinted;
}
_mint(to, tokenId);
cardSizes[tokenId] = DNACardLib.CardSize(cardSize);
cardSkins[tokenId] = cardSkin;
return tokenId;
}
function totalSupply() public view returns (uint256) {
return smallMinted + mediumMinted + largeMinted - totalRevealed;
}
function getCardSize(uint256 tokenId) public view returns (DNACardLib.CardSize) {
return cardSizes[tokenId];
}
function getCardSkin(uint256 tokenId) public view returns (uint8) {
return cardSkins[tokenId];
}
function setBaseURI(string memory newBaseURI) external onlyOwner {
baseURI = newBaseURI;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
return string(abi.encodePacked(baseURI, tokenId.toString()));
}
function setDefaultRoyalty(address receiver, uint96 feeNumerator) external onlyOwner {
_setDefaultRoyalty(receiver, feeNumerator);
}
function setTokenRoyalty(address receiver, uint256 tokenId, uint96 feeNumerator) external onlyOwner {
_setTokenRoyalty(tokenId, receiver, feeNumerator);
}
receive() external payable {
revert("Direct ETH transfers not allowed");
}
}
文件 9 的 45:DNACardLib.sol
pragma solidity ^0.8.4;
library DNACardLib {
enum CardSize {
SMALL,
MEDIUM,
LARGE
}
}
文件 10 的 45:DNACardReveal.sol
pragma solidity ^0.8.4;
import "@limitbreak/creator-token-standards/src/access/OwnableBasic.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./DNACardLib.sol";
import "./GEAR.sol";
contract DNACardReveal is OwnableBasic {
using Address for address;
using Strings for uint256;
uint256 public constant COMMON_SUPPLY = 777;
uint256 public constant UNCOMMON_SUPPLY = 550;
uint256 public constant RARE_SUPPLY = 275;
uint256 public constant EPIC_SUPPLY = 155;
uint256 public constant LEGENDARY_SUPPLY = 34;
mapping(uint256 => uint256) public gearRemainingSupply;
address public DNA_CARD_ADDRESS;
GEAR public gearContract;
uint256 public constant SELECTION_TIME_LIMIT = 20 minutes;
uint256 public constant SELECTION_TIME_LIMIT_BUFFER = 5 minutes;
mapping(uint256 => uint256) public revealTimestamps;
struct CategoryTracker {
bool hasTopBodysuit;
bool hasPantsSkirt;
bool hasShoesBoots;
bool hasHair;
uint256 remainingItems;
}
mapping(uint256 => DNACardLib.CardSize) public cardTypes;
mapping(uint256 => bool) public isRevealed;
mapping(uint256 => bool) public isHarvested;
mapping(uint256 => uint256[]) public revealedGear;
struct RevealConfig {
uint256 legendaryCount;
uint256 epicOrRareCount;
uint256 uncommonCount;
uint256 commonCount;
uint256 colorCount;
uint256 totalGearCount;
}
struct HarvestConfig {
uint256 legendaryCount;
uint256 rareOrEpicCount;
uint256 uncommonCount;
uint256 commonCount;
uint256 totalHarvestCount;
}
struct SelectionParams {
GEARMetadata.Rarity rarity;
address to;
uint256 tokenId;
uint256 nonce;
uint256[] alreadyRevealedGear;
bool excludeSpecialCategories;
CategoryTracker tracker;
}
struct ValidationParams {
uint256 candidate;
uint256[] alreadyRevealedGear;
bool needsForcedCategories;
string[] forcedCategories;
bool excludeSpecialCategories;
CategoryTracker tracker;
}
struct GearCounts {
uint256 legendaryCount;
uint256 epicCount;
uint256 rareCount;
uint256 uncommonCount;
uint256 commonCount;
}
mapping(DNACardLib.CardSize => RevealConfig) public revealConfigs;
mapping(DNACardLib.CardSize => HarvestConfig) public harvestConfigs;
function setGearContract(address payable gearContractAddress) external onlyOwner {
require(gearContractAddress != address(0), "Invalid gear contract address");
gearContract = GEAR(gearContractAddress);
}
function setDnaCardAddress(address dnaCardAddress) external onlyOwner {
require(dnaCardAddress != address(0), "Invalid DNA Card contract address");
DNA_CARD_ADDRESS = dnaCardAddress;
}
modifier onlyDnaCard() {
require(msg.sender == DNA_CARD_ADDRESS, "Caller is not the DNA Card contract");
_;
}
constructor(address payable gearContractAddress_) {
gearContract = GEAR(gearContractAddress_);
resetGearRemainingSupply();
revealConfigs[DNACardLib.CardSize.SMALL] = RevealConfig({
legendaryCount: 0,
epicOrRareCount: 1,
uncommonCount: 3,
commonCount: 6,
colorCount: 2,
totalGearCount: 13
});
revealConfigs[DNACardLib.CardSize.MEDIUM] = RevealConfig({
legendaryCount: 0,
epicOrRareCount: 2,
uncommonCount: 8,
commonCount: 18,
colorCount: 3,
totalGearCount: 32
});
revealConfigs[DNACardLib.CardSize.LARGE] = RevealConfig({
legendaryCount: 1,
epicOrRareCount: 3,
uncommonCount: 6,
commonCount: 10,
colorCount: 4,
totalGearCount: 25
});
harvestConfigs[DNACardLib.CardSize.SMALL] = HarvestConfig({
legendaryCount: 0,
rareOrEpicCount: 1,
uncommonCount: 2,
commonCount: 4,
totalHarvestCount: 7
});
harvestConfigs[DNACardLib.CardSize.MEDIUM] = HarvestConfig({
legendaryCount: 0,
rareOrEpicCount: 1,
uncommonCount: 6,
commonCount: 12,
totalHarvestCount: 19
});
harvestConfigs[DNACardLib.CardSize.LARGE] = HarvestConfig({
legendaryCount: 1,
rareOrEpicCount: 1,
uncommonCount: 4,
commonCount: 6,
totalHarvestCount: 12
});
}
function resetGearRemainingSupply() public onlyOwner {
require(address(gearContract) != address(0), "Gear contract not set");
uint256[] memory commonGear = gearContract.getRarityNFTAssetIds(GEARMetadata.Rarity.COMMON);
uint256[] memory uncommonGear = gearContract.getRarityNFTAssetIds(GEARMetadata.Rarity.UNCOMMON);
uint256[] memory rareGear = gearContract.getRarityNFTAssetIds(GEARMetadata.Rarity.RARE);
uint256[] memory epicGear = gearContract.getRarityNFTAssetIds(GEARMetadata.Rarity.EPIC);
uint256[] memory legendaryGear = gearContract.getRarityNFTAssetIds(GEARMetadata.Rarity.LEGENDARY);
for (uint256 i = 0; i < commonGear.length; i++) {
if (commonGear[i] != 0) {
gearRemainingSupply[commonGear[i]] = COMMON_SUPPLY;
}
}
for (uint256 i = 0; i < uncommonGear.length; i++) {
if (uncommonGear[i] != 0) {
gearRemainingSupply[uncommonGear[i]] = UNCOMMON_SUPPLY;
}
}
for (uint256 i = 0; i < rareGear.length; i++) {
if (rareGear[i] != 0) {
gearRemainingSupply[rareGear[i]] = RARE_SUPPLY;
}
}
for (uint256 i = 0; i < epicGear.length; i++) {
if (epicGear[i] != 0) {
gearRemainingSupply[epicGear[i]] = EPIC_SUPPLY;
}
}
for (uint256 i = 0; i < legendaryGear.length; i++) {
if (legendaryGear[i] != 0) {
gearRemainingSupply[legendaryGear[i]] = LEGENDARY_SUPPLY;
}
}
}
function overrideGearCategoryRemainingSupply(string memory category, uint256 remainingSupply) external onlyOwner {
require(address(gearContract) != address(0), "Gear contract not set");
require(remainingSupply > 0, "Remaining supply must be greater than 0");
uint256[] memory categoryGear = gearContract.getCategoryNFTAssetIds(category);
for (uint256 i = 0; i < categoryGear.length; i++) {
if (categoryGear[i] != 0) {
gearRemainingSupply[categoryGear[i]] = remainingSupply;
}
}
}
function overrideGearRemainingSupply(uint256 tokenId, uint256 remainingSupply) external onlyOwner {
require(remainingSupply > 0, "Remaining supply must be greater than 0");
gearRemainingSupply[tokenId] = remainingSupply;
}
function reveal(address to, uint256 tokenId, DNACardLib.CardSize cardSize, uint8 cardSkin) public onlyDnaCard returns (uint256[] memory) {
require(address(gearContract) != address(0), "Gear contract not set");
require(!isRevealed[tokenId], "DNA Card already revealed");
RevealConfig memory config = revealConfigs[cardSize];
uint256[] memory selectedGear = new uint256[](config.totalGearCount);
uint256 selectedCount = 0;
uint256 nonce = 0;
revealTimestamps[tokenId] = block.timestamp;
CategoryTracker memory tracker = CategoryTracker({
hasTopBodysuit: false,
hasPantsSkirt: false,
hasShoesBoots: false,
hasHair: false,
remainingItems: config.totalGearCount - config.colorCount - 1
});
if (config.legendaryCount > 0) {
selectedGear[selectedCount++] = _selectGearByRarity(GEARMetadata.Rarity.LEGENDARY, to, tokenId, nonce++, selectedGear, true, tracker);
}
for (uint256 i = 0; i < config.epicOrRareCount; i++) {
selectedGear[selectedCount++] = _selectGearByRarity(
_randomEpicRareRoll(tokenId, nonce++) ? GEARMetadata.Rarity.EPIC : GEARMetadata.Rarity.RARE,
to,
tokenId,
nonce++,
selectedGear,
true,
tracker
);
}
for (uint256 i = 0; i < config.uncommonCount; i++) {
selectedGear[selectedCount++] = _selectGearByRarity(GEARMetadata.Rarity.UNCOMMON, to, tokenId, nonce++, selectedGear, true, tracker);
}
for (uint256 i = 0; i < config.commonCount; i++) {
selectedGear[selectedCount++] = _selectGearByRarity(GEARMetadata.Rarity.COMMON, to, tokenId, nonce++, selectedGear, true, tracker);
}
selectedGear[selectedCount++] = _selectSkinType(cardSkin);
uint256[] memory selectedColors = _selectColors(cardSize, tokenId, nonce);
for (uint256 i = 0; i < selectedColors.length; i++) {
selectedGear[selectedCount++] = selectedColors[i];
}
for (uint256 i = 0; i < selectedGear.length; i++) {
gearRemainingSupply[selectedGear[i]]--;
}
revealedGear[tokenId] = selectedGear;
isRevealed[tokenId] = true;
return selectedGear;
}
function _selectGearByRarity(
GEARMetadata.Rarity rarity,
address to,
uint256 tokenId,
uint256 nonce,
uint256[] memory alreadyRevealedGear,
bool excludeSpecialCategories,
CategoryTracker memory tracker
) internal view returns (uint256) {
SelectionParams memory params = SelectionParams({
rarity: rarity,
to: to,
tokenId: tokenId,
nonce: nonce,
alreadyRevealedGear: alreadyRevealedGear,
excludeSpecialCategories: excludeSpecialCategories,
tracker: tracker
});
return _performGearSelection(params);
}
function _performGearSelection(SelectionParams memory params) internal view returns (uint256) {
uint256[] memory rarityTokens = gearContract.getRarityNFTAssetIds(params.rarity);
require(rarityTokens.length > 0, "No tokens available for this rarity");
uint256 maxAttempts = 1000;
uint256 attempts = 0;
string[] memory forcedCategories = _needsForcedCategories(params.tracker);
bool needsForcedCategories = forcedCategories.length > 0;
uint256 totalRemaining = 0;
for (uint256 i = 0; i < rarityTokens.length; i++) {
if (rarityTokens[i] != 0) {
totalRemaining += gearRemainingSupply[rarityTokens[i]];
}
}
require(totalRemaining > 0, "No remaining supply for this rarity");
while (attempts < maxAttempts) {
bytes32 randomHash = keccak256(abi.encodePacked(block.timestamp, block.prevrandao, params.to, params.tokenId, params.nonce, attempts));
uint256 randomNum = uint256(randomHash) % totalRemaining;
uint256 cumulative = 0;
for (uint256 i = 0; i < rarityTokens.length; i++) {
uint256 candidate = rarityTokens[i];
if (candidate == 0) continue;
cumulative += gearRemainingSupply[candidate];
if (randomNum < cumulative) {
ValidationParams memory validationParams = ValidationParams({
candidate: candidate,
alreadyRevealedGear: params.alreadyRevealedGear,
needsForcedCategories: needsForcedCategories,
forcedCategories: forcedCategories,
excludeSpecialCategories: params.excludeSpecialCategories,
tracker: params.tracker
});
if (_isValidCandidate(validationParams)) {
return candidate;
}
break;
}
}
attempts++;
}
revert("Could not find valid gear after maximum attempts");
}
function _isValidCandidate(ValidationParams memory params) internal view returns (bool) {
for (uint256 i = 0; i < params.alreadyRevealedGear.length; i++) {
if (params.candidate == params.alreadyRevealedGear[i]) {
return false;
}
}
string memory category = gearContract.getDrifterAssetCategory(params.candidate);
if (params.needsForcedCategories) {
if (_categoryMatches(category, params.forcedCategories)) {
_updateCategoryTracker(params.tracker, category);
return true;
}
} else {
if (!params.excludeSpecialCategories || !_isSpecialCategory(category)) {
_updateCategoryTracker(params.tracker, category);
return true;
}
}
return false;
}
function _selectSkinType(uint8 cardSkin) internal view returns (uint256) {
require(cardSkin > 0 && cardSkin <= 9, "Invalid token type");
uint256[] memory skinTokens = gearContract.getCategoryNFTAssetIds("Skin Type");
require(skinTokens.length > 0, "No skin types available");
require(cardSkin <= skinTokens.length, "Token type exceeds available skin types");
return skinTokens[cardSkin - 1];
}
function _selectColors(DNACardLib.CardSize cardSize, uint256 tokenId, uint256 nonce) internal view returns (uint256[] memory) {
uint256 colorCount = revealConfigs[cardSize].colorCount;
uint256[] memory selectedColors = new uint256[](colorCount);
uint256[] memory availableColors = gearContract.getCategoryNFTAssetIds("Color");
require(availableColors.length > 0, "No colors available");
uint256[] memory indices = new uint256[](availableColors.length);
for (uint256 i = 0; i < availableColors.length; i++) {
indices[i] = i;
}
for (uint256 i = availableColors.length - 1; i > 0; i--) {
uint256 randomValue = uint256(keccak256(abi.encodePacked(tokenId, nonce, i)));
uint256 j = randomValue % (i + 1);
uint256 temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}
for (uint256 i = 0; i < colorCount; i++) {
selectedColors[i] = availableColors[indices[i]];
}
return selectedColors;
}
function _isSpecialCategory(string memory category) internal pure returns (bool) {
return _isSkinType(category) || _isColor(category);
}
function _isSkinType(string memory category) internal pure returns (bool) {
bytes32 categoryHash = keccak256(abi.encodePacked(category));
bytes32 skinTypeHash = keccak256(abi.encodePacked("Skin Type"));
return categoryHash == skinTypeHash;
}
function _isColor(string memory category) internal pure returns (bool) {
bytes32 categoryHash = keccak256(abi.encodePacked(category));
bytes32 colorHash = keccak256(abi.encodePacked("Color"));
return categoryHash == colorHash;
}
function _updateCategoryTracker(CategoryTracker memory tracker, string memory category) internal pure {
if (_categoryMatches(category, _getRequiredCategory(0))) {
tracker.hasTopBodysuit = true;
} else if (_categoryMatches(category, _getRequiredCategory(1))) {
tracker.hasPantsSkirt = true;
} else if (_categoryMatches(category, _getRequiredCategory(2))) {
tracker.hasShoesBoots = true;
} else if (_categoryMatches(category, _getRequiredCategory(3))) {
tracker.hasHair = true;
}
if (tracker.remainingItems > 0) {
tracker.remainingItems--;
}
}
function _needsForcedCategories(CategoryTracker memory tracker) internal pure returns (string[] memory) {
uint256 FORCE_THRESHOLD = 4;
if (tracker.remainingItems > FORCE_THRESHOLD) {
return new string[](0);
}
if (!tracker.hasTopBodysuit) return _getRequiredCategory(0);
if (!tracker.hasPantsSkirt) return _getRequiredCategory(1);
if (!tracker.hasShoesBoots) return _getRequiredCategory(2);
if (!tracker.hasHair) return _getRequiredCategory(3);
return new string[](0);
}
function _randomEpicRareRoll(uint256 tokenId, uint256 nonce) internal pure returns (bool) {
return uint256(keccak256(abi.encodePacked(tokenId, nonce))) % 5 == 0;
}
function _autoSelectAndHarvestGear(address to, uint256 tokenId, DNACardLib.CardSize cardSize) internal returns (uint256[] memory) {
(uint256[] memory selectedGear, uint256[] memory specialGear) = _selectGearForHarvest(tokenId, cardSize);
return _performHarvest(to, tokenId, selectedGear, specialGear);
}
function _selectGearForHarvest(uint256 tokenId, DNACardLib.CardSize cardSize) private view returns (uint256[] memory, uint256[] memory) {
HarvestConfig memory config = harvestConfigs[cardSize];
uint256[] memory availableGear = revealedGear[tokenId];
uint256[] memory selectedGear = new uint256[](config.totalHarvestCount);
uint256[] memory specialGear = new uint256[](revealConfigs[cardSize].colorCount + 1);
uint256 selectedCount;
uint256 specialCount;
uint256[] memory legendaryGear = new uint256[](availableGear.length);
uint256[] memory epicGear = new uint256[](availableGear.length);
uint256[] memory rareGear = new uint256[](availableGear.length);
uint256[] memory uncommonGear = new uint256[](availableGear.length);
uint256[] memory commonGear = new uint256[](availableGear.length);
GearCounts memory counts;
for (uint256 i = 0; i < availableGear.length; i++) {
uint256 gearId = availableGear[i];
string memory category = gearContract.getDrifterAssetCategory(gearId);
if (_isSpecialCategory(category)) {
specialGear[specialCount++] = gearId;
continue;
}
GEARMetadata.Rarity rarity = gearContract.getDrifterAssetRarity(gearId);
if (rarity == GEARMetadata.Rarity.LEGENDARY) {
legendaryGear[counts.legendaryCount++] = gearId;
} else if (rarity == GEARMetadata.Rarity.EPIC) {
epicGear[counts.epicCount++] = gearId;
} else if (rarity == GEARMetadata.Rarity.RARE) {
rareGear[counts.rareCount++] = gearId;
} else if (rarity == GEARMetadata.Rarity.UNCOMMON) {
uncommonGear[counts.uncommonCount++] = gearId;
} else if (rarity == GEARMetadata.Rarity.COMMON) {
commonGear[counts.commonCount++] = gearId;
}
}
for (uint256 i = 0; i < config.legendaryCount && i < counts.legendaryCount; i++) {
selectedGear[selectedCount++] = legendaryGear[i];
}
uint256 epicRareNeeded = config.rareOrEpicCount;
uint256 epicsTaken = 0;
for (uint256 i = 0; i < counts.epicCount && epicRareNeeded > 0; i++) {
selectedGear[selectedCount++] = epicGear[i];
epicsTaken++;
epicRareNeeded--;
}
if (epicRareNeeded > 0) {
for (uint256 i = 0; i < counts.rareCount && epicRareNeeded > 0; i++) {
selectedGear[selectedCount++] = rareGear[i];
epicRareNeeded--;
}
}
for (uint256 i = 0; i < config.uncommonCount && i < counts.uncommonCount; i++) {
selectedGear[selectedCount++] = uncommonGear[i];
}
for (uint256 i = 0; i < config.commonCount && i < counts.commonCount; i++) {
selectedGear[selectedCount++] = commonGear[i];
}
return (selectedGear, specialGear);
}
function _performHarvest(address to, uint256 tokenId, uint256[] memory selectedGear, uint256[] memory specialGear) private returns (uint256[] memory) {
for (uint256 i = 0; i < selectedGear.length; i++) {
if (selectedGear[i] != 0) {
gearContract.mint(to, selectedGear[i], 1);
if (gearRemainingSupply[selectedGear[i]] > 0) {
gearRemainingSupply[selectedGear[i]]--;
}
}
}
for (uint256 i = 0; i < specialGear.length; i++) {
if (specialGear[i] != 0) {
gearContract.mint(to, specialGear[i], 1);
}
}
uint256 totalLength = selectedGear.length;
for (uint256 i = 0; i < specialGear.length; i++) {
if (specialGear[i] != 0) totalLength++;
}
uint256[] memory allGear = new uint256[](totalLength);
uint256 index = 0;
for (uint256 i = 0; i < selectedGear.length; i++) {
if (selectedGear[i] != 0) {
allGear[index++] = selectedGear[i];
}
}
for (uint256 i = 0; i < specialGear.length; i++) {
if (specialGear[i] != 0) {
allGear[index++] = specialGear[i];
}
}
isHarvested[tokenId] = true;
return allGear;
}
function getRevealedGear(uint256 tokenId) external view returns (uint256[] memory) {
require(isRevealed[tokenId], "DNA Card not revealed yet");
return revealedGear[tokenId];
}
function getRemainingSelectionTime(uint256 tokenId) external view returns (uint256) {
uint256 revealTime = revealTimestamps[tokenId];
if (revealTime == 0) return 0;
uint256 endTime = revealTime + SELECTION_TIME_LIMIT;
if (block.timestamp >= endTime) return 0;
return endTime - block.timestamp;
}
function _validateSelectedGear(
uint256[] calldata selectedGearIds,
uint256[] memory availableGear,
HarvestConfig memory config
) private view returns (uint256[] memory) {
require(selectedGearIds.length == config.totalHarvestCount, "Invalid number of selected gear");
uint256 selectedLegendary;
uint256 selectedRareOrEpic;
uint256 selectedUncommon;
uint256 selectedCommon;
for (uint256 i = 0; i < selectedGearIds.length; i++) {
require(!_isSpecialCategory(gearContract.getDrifterAssetCategory(selectedGearIds[i])), "Cannot choose a special category as a gear");
bool found = false;
for (uint256 j = 0; j < availableGear.length; j++) {
if (selectedGearIds[i] == availableGear[j]) {
found = true;
GEARMetadata.Rarity rarity = gearContract.getDrifterAssetRarity(selectedGearIds[i]);
if (rarity == GEARMetadata.Rarity.LEGENDARY) {
selectedLegendary++;
} else if (rarity == GEARMetadata.Rarity.EPIC || rarity == GEARMetadata.Rarity.RARE) {
selectedRareOrEpic++;
} else if (rarity == GEARMetadata.Rarity.UNCOMMON) {
selectedUncommon++;
} else if (rarity == GEARMetadata.Rarity.COMMON) {
selectedCommon++;
}
break;
}
}
require(found, "Selected gear not in revealed set");
}
require(selectedLegendary == config.legendaryCount, "Invalid legendary count");
require(selectedRareOrEpic == config.rareOrEpicCount, "Invalid rare/epic count");
require(selectedUncommon == config.uncommonCount, "Invalid uncommon count");
require(selectedCommon == config.commonCount, "Invalid common count");
return selectedGearIds;
}
function _getSpecialGear(uint256[] memory availableGear, DNACardLib.CardSize cardSize) private view returns (uint256[] memory, uint256) {
uint256[] memory specialGear = new uint256[](revealConfigs[cardSize].colorCount + 1);
uint256 specialCount;
for (uint256 i = 0; i < availableGear.length; i++) {
string memory category = gearContract.getDrifterAssetCategory(availableGear[i]);
if (_isSpecialCategory(category)) {
specialGear[specialCount++] = availableGear[i];
}
}
return (specialGear, specialCount);
}
function _mintSelectedGear(
address to,
uint256[] memory selectedGear,
uint256[] memory specialGear,
uint256 specialCount
) private returns (uint256[] memory) {
uint256 totalGear = selectedGear.length + specialCount;
for (uint256 i = 0; i < selectedGear.length; i++) {
gearContract.mint(to, selectedGear[i], 1);
if (gearRemainingSupply[selectedGear[i]] > 0) {
gearRemainingSupply[selectedGear[i]]--;
}
}
for (uint256 i = 0; i < specialCount; i++) {
gearContract.mint(to, specialGear[i], 1);
}
uint256[] memory allGear = new uint256[](totalGear);
for (uint256 i = 0; i < selectedGear.length; i++) {
allGear[i] = selectedGear[i];
}
for (uint256 i = 0; i < specialCount; i++) {
allGear[selectedGear.length + i] = specialGear[i];
}
return allGear;
}
function harvestReveal(
address to,
uint256 tokenId,
DNACardLib.CardSize cardSize,
uint256[] calldata selectedGearIds
) public onlyDnaCard returns (uint256[] memory) {
require(address(gearContract) != address(0), "Gear contract not set");
require(isRevealed[tokenId], "DNA Card not revealed yet");
require(!isHarvested[tokenId], "DNA Card already harvested");
uint256 revealTime = revealTimestamps[tokenId];
require(revealTime > 0, "Invalid reveal timestamp");
uint256[] memory availableGear = revealedGear[tokenId];
for (uint256 i = 0; i < availableGear.length; i++) {
gearRemainingSupply[availableGear[i]]++;
}
if (block.timestamp > revealTime + SELECTION_TIME_LIMIT + SELECTION_TIME_LIMIT_BUFFER) {
return _autoSelectAndHarvestGear(to, tokenId, cardSize);
}
HarvestConfig memory config = harvestConfigs[cardSize];
require(availableGear.length > 0, "No revealed gear found");
uint256[] memory validatedGear = _validateSelectedGear(selectedGearIds, availableGear, config);
(uint256[] memory specialGear, uint256 specialCount) = _getSpecialGear(availableGear, cardSize);
uint256[] memory allGear = _mintSelectedGear(to, validatedGear, specialGear, specialCount);
isHarvested[tokenId] = true;
return allGear;
}
function _getRequiredCategory(uint256 index) internal pure returns (string[] memory) {
string[] memory categories;
if (index == 0) {
categories = new string[](6);
categories[0] = "Tops/Bodysuits";
categories[1] = "Bras";
categories[2] = "Jackets & Coats";
categories[3] = "Vests";
categories[4] = "Dresses";
categories[5] = "Jumpsuits";
} else if (index == 1) {
categories = new string[](5);
categories[0] = "Leggings";
categories[1] = "Leggings/Tights";
categories[2] = "Pants/Shorts";
categories[3] = "Skirts";
categories[4] = "Tights";
} else if (index == 2) {
categories = new string[](7);
categories[0] = "Boots";
categories[1] = "Flats";
categories[2] = "Heels";
categories[3] = "Sandals";
categories[4] = "Slippers";
categories[5] = "Sneakers";
categories[6] = "Formal";
} else if (index == 3) {
categories = new string[](5);
categories[0] = "Hair";
categories[1] = "Hats";
categories[2] = "Head Hovers";
categories[3] = "Headbands";
categories[4] = "Helmets";
} else {
revert("Invalid category index");
}
return categories;
}
function _categoryMatches(string memory category, string[] memory categories) internal pure returns (bool) {
for (uint256 i = 0; i < categories.length; i++) {
if (_compareStrings(category, categories[i])) {
return true;
}
}
return false;
}
function _compareStrings(string memory a, string memory b) internal pure returns (bool) {
return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
}
receive() external payable {
revert("Direct ETH transfers not allowed");
}
}
文件 11 的 45:Drifter.sol
pragma solidity ^0.8.4;
import "@limitbreak/creator-token-standards/src/erc721c/ERC721C.sol";
import "@limitbreak/creator-token-standards/src/access/OwnableBasic.sol";
import "@limitbreak/creator-token-standards/src/programmable-royalties/BasicRoyalties.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./GEAR.sol";
import "./BioCanvas.sol";
import "./DrifterName.sol";
import "./DrifterEquip.sol";
contract Drifter is ERC721C, DrifterName, DrifterEquip, BasicRoyalties, OwnableBasic {
using Address for address;
using Strings for uint256;
uint96 public constant ROYALTY_FEE_NUMERATOR = 500;
uint256 public latestTokenId = 0;
uint256 public totalSupply = 0;
string public baseURI = "https://m.cyberbrokers.com/base/drifter/";
BioCanvas public bioCanvasContract;
mapping(uint256 => uint256) public drifterAttributeCount;
mapping(uint256 => string[]) public drifterAttributeKeys;
mapping(uint256 => uint256[]) public drifterAttributeValues;
mapping(bytes32 => bool) public promoCodesUsed;
mapping(bytes32 => bool) public validPromoCodes;
event DrifterCreated(
uint256 indexed drifterId,
uint256 bioCanvasId,
uint256[] assetIds,
uint256[] assetColors,
string[] attributeKeys,
uint256[] attributeValues,
string name
);
event DrifterEdited(uint256 indexed drifterId, uint256[] assetIds, uint256[] assetColors, string[] attributeKeys, uint256[] attributeValues, string name);
modifier onlyBioCanvas() {
require(msg.sender == address(bioCanvasContract), "Caller is not the bio canvas contract");
_;
}
modifier onlyTokenOwner(uint256 tokenId) {
require(_isApprovedOrOwner(msg.sender, tokenId), "Caller is not owner nor approved");
_;
}
constructor(
string memory name_,
string memory symbol_,
address payable bioCanvasAddress_,
address payable gearAddress_,
address payable royaltyReceiver_
) ERC721OpenZeppelin(name_, symbol_) DrifterName() DrifterEquip(gearAddress_) BasicRoyalties(royaltyReceiver_, ROYALTY_FEE_NUMERATOR) {
bioCanvasContract = BioCanvas(bioCanvasAddress_);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721C, ERC1155Receiver, ERC2981) returns (bool) {
return super.supportsInterface(interfaceId);
}
function createDrifter(
uint256 bioCanvasId,
uint256[] calldata assetIds,
uint256[] calldata assetColors,
string[] calldata _attributeKeys,
uint256[] calldata _attributeValues,
uint256 namePlacement,
string calldata expectedName,
string calldata promoCode
) external payable returns (uint256) {
require(bioCanvasContract.balanceOf(_msgSender(), bioCanvasId) > 0, "Caller does not own the BioCanvas");
require(bioCanvasContract.convertToDrifter(bioCanvasId, 1, _msgSender()), "Failed to convert BioCanvas to Drifter");
uint256 drifterId = mint(_msgSender());
if (namePlacement < 2 ** 255) {
_confirmRolledName(drifterId, namePlacement, expectedName, _msgSender());
} else {
string memory paymentMethod = msg.value > 0 ? "ETH" : "USDC";
setDrifterName(drifterId, expectedName, promoCode, paymentMethod);
}
if (assetIds.length > 0) {
_equipGear(drifterId, assetIds, _msgSender());
}
if (assetColors.length > 0) {
_updateDrifterColors(drifterId, assetColors);
}
drifterAttributeCount[drifterId] = _attributeKeys.length;
drifterAttributeKeys[drifterId] = _attributeKeys;
drifterAttributeValues[drifterId] = _attributeValues;
emit DrifterCreated(drifterId, bioCanvasId, assetIds, assetColors, _attributeKeys, _attributeValues, expectedName);
return drifterId;
}
function editDrifterGear(
uint256 drifterId,
uint256[] calldata assetIds,
uint256[] calldata assetColors,
string[] calldata _attributeKeys,
uint256[] calldata _attributeValues
) external onlyTokenOwner(drifterId) {
_equipGear(drifterId, assetIds, msg.sender);
if (assetColors.length > 0) {
_updateDrifterColors(drifterId, assetColors);
}
_updateDrifterAttributes(drifterId, _attributeKeys, _attributeValues);
emit DrifterEdited(drifterId, assetIds, assetColors, drifterAttributeKeys[drifterId], drifterAttributeValues[drifterId], drifterNames[drifterId]);
}
function editDrifterAttributes(
uint256 drifterId,
string[] calldata _attributeKeys,
uint256[] calldata _attributeValues
) external onlyTokenOwner(drifterId) {
_updateDrifterAttributes(drifterId, _attributeKeys, _attributeValues);
emit DrifterEdited(
drifterId,
equippedGear[drifterId],
equippedGearColors[drifterId],
drifterAttributeKeys[drifterId],
drifterAttributeValues[drifterId],
drifterNames[drifterId]
);
}
function _updateDrifterAttributes(uint256 drifterId, string[] calldata _attributeKeys, uint256[] calldata _attributeValues) internal {
for (uint256 i = 0; i < _attributeKeys.length; i++) {
string memory key = _attributeKeys[i];
uint256 value = _attributeValues[i];
bool found = false;
for (uint256 j = 0; j < drifterAttributeKeys[drifterId].length; j++) {
if (keccak256(abi.encodePacked(drifterAttributeKeys[drifterId][j])) == keccak256(abi.encodePacked(key))) {
drifterAttributeValues[drifterId][j] = value;
found = true;
break;
}
}
if (!found) {
drifterAttributeCount[drifterId]++;
drifterAttributeKeys[drifterId].push(key);
drifterAttributeValues[drifterId].push(value);
}
}
}
function confirmDrifterName(uint256 drifterId, uint256 placement, string calldata expectedName) external onlyTokenOwner(drifterId) {
_confirmRolledName(drifterId, placement, expectedName, _msgSender());
}
function setDrifterName(
uint256 drifterId,
string calldata name,
string calldata promoCode,
string memory paymentMethod
) public payable onlyTokenOwner(drifterId) {
if (bytes(promoCode).length == 0) {
if (keccak256(bytes(paymentMethod)) == keccak256(bytes("ETH"))) {
require(msg.value >= getNameCreationCost(name, paymentMethod), "Insufficient payment");
} else if (keccak256(bytes(paymentMethod)) == keccak256(bytes("USDC"))) {
uint256 price = getNameCreationCost(name, paymentMethod);
require(usdcContract.balanceOf(msg.sender) >= price, "Insufficient USDC balance");
require(usdcContract.allowance(msg.sender, address(this)) >= price, "Insufficient USDC allowance");
require(usdcContract.transferFrom(msg.sender, address(this), price), "USDC transfer failed");
}
} else {
require(isValidUnusedPromoCode(promoCode), "Invalid or used promo code");
bytes32 promoCodeHash = keccak256(abi.encodePacked(promoCode));
promoCodesUsed[promoCodeHash] = true;
}
_createName(drifterId, name);
}
function mint(address to) internal returns (uint256) {
_mint(to, ++latestTokenId);
totalSupply++;
return latestTokenId;
}
function setBaseURI(string memory newBaseURI) external onlyOwner {
baseURI = newBaseURI;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
return string(abi.encodePacked(baseURI, tokenId.toString()));
}
function addPromoCodeHash(bytes32 promoCodeHash) external onlyOwner {
require(promoCodeHash != 0, "Promo code hash cannot be zero");
validPromoCodes[promoCodeHash] = true;
}
function removePromoCodeHash(bytes32 promoCodeHash) external onlyOwner {
validPromoCodes[promoCodeHash] = false;
}
function isValidUnusedPromoCode(string memory promoCode) public view returns (bool) {
if (bytes(promoCode).length == 0) return false;
bytes32 promoCodeHash = keccak256(abi.encodePacked(promoCode));
return validPromoCodes[promoCodeHash] && !promoCodesUsed[promoCodeHash];
}
function setDrifterNamePrices(uint64[] memory ethPrices, uint64[] memory usdcPrices) external onlyOwner {
_setDrifterNamePrices(ethPrices, usdcPrices);
}
function addNames(string[] memory newNames) external onlyOwner {
_addNames(newNames);
}
function addDisallowedNames(string[] memory newNames) external onlyOwner {
_addDisallowedNames(newNames);
}
function addRestrictedWords(string[] memory words) external onlyOwner {
_addRestrictedWords(words);
}
function withdraw() external onlyOwner {
payable(owner()).transfer(address(this).balance);
}
function withdrawUsdc() external onlyOwner {
usdcContract.transfer(owner(), usdcContract.balanceOf(address(this)));
}
function setUsdcAddress(address _newUsdcAddress) external onlyOwner {
usdcContract = IERC20(_newUsdcAddress);
}
function setDefaultRoyalty(address receiver, uint96 feeNumerator) external onlyOwner {
_setDefaultRoyalty(receiver, feeNumerator);
}
function setTokenRoyalty(address receiver, uint256 tokenId, uint96 feeNumerator) external onlyOwner {
_setTokenRoyalty(tokenId, receiver, feeNumerator);
}
function adminSetDrifterName(uint256 drifterId, string calldata name) external onlyOwner {
require(_exists(drifterId), "ERC721: operator query for nonexistent token");
require(!usedNames[name], "Name already in use");
_setName(drifterId, name);
}
receive() external payable {
revert("Direct ETH transfers not allowed");
}
}
文件 12 的 45:DrifterEquip.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import "./GEAR.sol";
abstract contract DrifterEquip is ERC1155Holder {
GEAR public gearContract;
mapping(uint256 => uint256[]) public equippedGear;
mapping(uint256 => uint256[]) public equippedGearColors;
constructor(address payable gearAddress_) {
gearContract = GEAR(gearAddress_);
}
function getEquippedGear(uint256 drifterId) external view returns (uint256[] memory) {
return equippedGear[drifterId];
}
function getEquippedGearColors(uint256 drifterId) external view returns (uint256[] memory) {
return equippedGearColors[drifterId];
}
function _updateDrifterColors(uint256 drifterId, uint256[] calldata colorIndexes) internal {
uint256[] memory currentGear = equippedGear[drifterId];
require(colorIndexes.length == currentGear.length, "Color indexes array must be the same length as equipped gear array");
for (uint256 i = 0; i < colorIndexes.length; i++) {
uint256 colorIndex = colorIndexes[i];
if (colorIndex == 0) continue;
string memory category = gearContract.getDrifterAssetCategory(colorIndex);
require(keccak256(abi.encodePacked(category)) == keccak256(abi.encodePacked("Color")), "Asset must be of category Color");
bool colorFound = false;
for (uint256 j = 0; j < currentGear.length; j++) {
if (currentGear[j] == colorIndex) {
colorFound = true;
break;
}
}
require(colorFound, "Color Asset not equipped on Drifter");
}
equippedGearColors[drifterId] = colorIndexes;
}
function _equipGear(uint256 drifterId, uint256[] calldata gearIds, address owner) internal {
uint256[] memory oldGearIds = equippedGear[drifterId];
if (oldGearIds.length > 0) {
for (uint256 i = 0; i < oldGearIds.length; i++) {
if (gearContract.isNonNFT(oldGearIds[i])) continue;
bool keepGear = false;
for (uint256 j = 0; j < gearIds.length; j++) {
if (oldGearIds[i] == gearIds[j]) {
keepGear = true;
break;
}
}
if (!keepGear) {
gearContract.safeTransferFrom(address(this), owner, oldGearIds[i], 1, "");
}
}
}
if (gearIds.length > 0) {
string[] memory usedCategories = new string[](gearIds.length);
uint256 categoryCount = 0;
for (uint256 i = 0; i < gearIds.length; i++) {
bool isAlreadyEquipped = false;
for (uint256 j = 0; j < oldGearIds.length; j++) {
if (gearIds[i] == oldGearIds[j]) {
isAlreadyEquipped = true;
string memory category = gearContract.getDrifterAssetCategory(gearIds[i]);
if (keccak256(abi.encodePacked(category)) != keccak256(abi.encodePacked("Color"))) {
bool categoryExists = false;
for (uint256 k = 0; k < categoryCount; k++) {
if (keccak256(abi.encodePacked(usedCategories[k])) == keccak256(abi.encodePacked(category))) {
categoryExists = true;
break;
}
}
if (!categoryExists) {
usedCategories[categoryCount++] = category;
}
}
break;
}
}
if (!isAlreadyEquipped) {
if (!gearContract.isNonNFT(gearIds[i])) {
require(gearContract.balanceOf(owner, gearIds[i]) > 0, "Owner does not own all specified GEAR");
gearContract.safeTransferFrom(owner, address(this), gearIds[i], 1, "");
}
string memory category = gearContract.getDrifterAssetCategory(gearIds[i]);
if (keccak256(abi.encodePacked(category)) != keccak256(abi.encodePacked("Color"))) {
bool categoryExists = false;
for (uint256 k = 0; k < categoryCount; k++) {
if (keccak256(abi.encodePacked(usedCategories[k])) == keccak256(abi.encodePacked(category))) {
categoryExists = true;
break;
}
}
require(!categoryExists, "Duplicate category not allowed");
usedCategories[categoryCount++] = category;
}
}
}
}
equippedGear[drifterId] = gearIds;
}
}
文件 13 的 45:DrifterName.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
abstract contract DrifterName {
using Strings for uint256;
string[] public names;
mapping(string => bool) public disallowedNames;
string[] public restrictedWords;
mapping(string => bool) public usedNames;
mapping(uint256 => string) public drifterNames;
uint64[5] public drifterNamePricesETH = [0.25 ether, 0.1 ether, 0.05 ether, 0.02 ether, 0.005 ether];
uint64[5] public drifterNamePricesUSDC = [575_000_000, 230_000_000, 115_000_000, 46_000_000, 11_500_000];
IERC20 public usdcContract;
event NameSet(uint256 indexed tokenId, string name);
function _setDrifterNamePrices(uint64[] memory ethPrices, uint64[] memory usdcPrices) internal {
require(ethPrices.length == 5, "Invalid number of ETH prices");
require(usdcPrices.length == 5, "Invalid number of USDC prices");
for (uint256 i = 0; i < 5; i++) {
require(ethPrices[i] > 0, "Invalid ETH price");
require(usdcPrices[i] > 0, "Invalid USDC price");
}
drifterNamePricesETH[0] = ethPrices[0];
drifterNamePricesETH[1] = ethPrices[1];
drifterNamePricesETH[2] = ethPrices[2];
drifterNamePricesETH[3] = ethPrices[3];
drifterNamePricesETH[4] = ethPrices[4];
drifterNamePricesUSDC[0] = usdcPrices[0];
drifterNamePricesUSDC[1] = usdcPrices[1];
drifterNamePricesUSDC[2] = usdcPrices[2];
drifterNamePricesUSDC[3] = usdcPrices[3];
drifterNamePricesUSDC[4] = usdcPrices[4];
}
function getNameCreationCost(string memory name, string memory paymentMethod) public view returns (uint256) {
uint256 length = bytes(name).length;
require(length <= 32, "Name too long");
require(!usedNames[name], "Name already in use");
bytes memory nameBytes = bytes(name);
for (uint i = 0; i < restrictedWords.length; i++) {
bytes memory restrictedWord = bytes(restrictedWords[i]);
if (_contains(nameBytes, restrictedWord)) {
revert("Name contains restricted word");
}
}
require(!disallowedNames[name], "Name is disallowed");
if (keccak256(bytes(paymentMethod)) == keccak256(bytes("ETH"))) {
if (length <= 3) return drifterNamePricesETH[0];
if (length == 4) return drifterNamePricesETH[1];
if (length == 5) return drifterNamePricesETH[2];
if (length == 6) return drifterNamePricesETH[3];
return drifterNamePricesETH[4];
} else if (keccak256(bytes(paymentMethod)) == keccak256(bytes("USDC"))) {
if (length <= 3) return drifterNamePricesUSDC[0];
if (length == 4) return drifterNamePricesUSDC[1];
if (length == 5) return drifterNamePricesUSDC[2];
if (length == 6) return drifterNamePricesUSDC[3];
return drifterNamePricesUSDC[4];
} else {
revert("Invalid payment method");
}
}
function _addNames(string[] memory newNames) internal {
for (uint256 i = 0; i < newNames.length; i++) {
if (bytes(newNames[i]).length > 0) {
names.push(newNames[i]);
}
}
}
function _addDisallowedNames(string[] memory newNames) internal {
for (uint256 i = 0; i < newNames.length; i++) {
if (bytes(newNames[i]).length > 0) {
disallowedNames[newNames[i]] = true;
}
}
}
function _addRestrictedWords(string[] memory words) internal {
for (uint256 i = 0; i < words.length; i++) {
if (bytes(words[i]).length > 0) {
restrictedWords.push(words[i]);
}
}
}
function rollName(address sender, uint256 placement) public view returns (string memory) {
return _rollName(sender, placement);
}
function _rollName(address rollSender, uint256 placement) internal view returns (string memory) {
require(names.length > 0, "Name list not initialized");
placement = placement % 10000;
string memory generatedName;
uint256 seed = uint256(keccak256(abi.encodePacked(rollSender, placement, "seed")));
do {
uint256 firstIndex = uint256(keccak256(abi.encodePacked(rollSender, placement, "first", seed))) % names.length;
seed = uint256(keccak256(abi.encodePacked(rollSender, placement, "second", seed)));
uint256 secondIndex = seed % names.length;
while (secondIndex == firstIndex) {
seed = uint256(keccak256(abi.encodePacked(seed)));
secondIndex = seed % names.length;
}
uint256 useThreeNames = uint256(keccak256(abi.encodePacked(rollSender, placement, "length", seed))) % 4;
if (useThreeNames == 0) {
seed = uint256(keccak256(abi.encodePacked(rollSender, placement, "third", seed)));
uint256 thirdIndex = seed % names.length;
while (thirdIndex == firstIndex || thirdIndex == secondIndex) {
seed = uint256(keccak256(abi.encodePacked(seed)));
thirdIndex = seed % names.length;
}
generatedName = string(abi.encodePacked(names[firstIndex], " ", names[secondIndex], " ", names[thirdIndex]));
} else {
generatedName = string(abi.encodePacked(names[firstIndex], " ", names[secondIndex]));
}
seed = uint256(keccak256(abi.encodePacked(seed)));
} while (usedNames[generatedName]);
return generatedName;
}
function _isValidNameFormat(string memory name) internal pure returns (bool) {
bytes memory nameBytes = bytes(name);
uint256 length = nameBytes.length;
if (nameBytes[0] == 0x20 || nameBytes[length - 1] == 0x20) {
return false;
}
bool lastWasSpace = false;
for (uint256 i = 0; i < length; i++) {
bytes1 char = nameBytes[i];
if (char == 0x20) {
if (lastWasSpace) {
return false;
}
lastWasSpace = true;
continue;
}
lastWasSpace = false;
if (char >= 0x61 && char <= 0x7A) {
continue;
}
if (char >= 0x41 && char <= 0x5A) {
continue;
}
if (char >= 0x30 && char <= 0x39) {
continue;
}
if (char == 0x2D) {
continue;
}
if (char == 0x5F) {
continue;
}
if (char == 0x27) {
continue;
}
return false;
}
return true;
}
function _confirmRolledName(uint256 tokenId, uint256 placement, string memory expectedName, address rollSender) internal {
require(bytes(drifterNames[tokenId]).length == 0, "Name already set for this token");
string memory generatedName = _rollName(rollSender, placement);
require(keccak256(abi.encodePacked(generatedName)) == keccak256(abi.encodePacked(expectedName)), "Generated name does not match expected name");
require(!_isNameInvalid(expectedName), "Invalid name");
require(!usedNames[expectedName], "Name already in use");
_setName(tokenId, expectedName);
}
function _createName(uint256 tokenId, string memory name) internal {
require(_isValidNameFormat(name), "Invalid name format");
require(!_isNameInvalid(name), "Invalid name");
require(!usedNames[name], "Name already in use");
require(bytes(name).length <= 32, "Name too long");
_setName(tokenId, name);
}
function _isNameInvalid(string memory name) internal view returns (bool) {
if (disallowedNames[name]) {
return true;
}
bytes memory nameBytes = bytes(name);
for (uint i = 0; i < restrictedWords.length; i++) {
bytes memory restrictedWord = bytes(restrictedWords[i]);
if (_contains(nameBytes, restrictedWord)) {
return true;
}
}
return false;
}
function _toLower(bytes1 char) internal pure returns (bytes1) {
if (char >= 0x41 && char <= 0x5A) {
return bytes1(uint8(char) + 32);
}
return char;
}
function _contains(bytes memory what, bytes memory where) internal pure returns (bool) {
if (where.length == 0 || what.length < where.length) {
return false;
}
for (uint256 i = 0; i <= what.length - where.length; i++) {
bool found = true;
for (uint256 j = 0; j < where.length; j++) {
if (_toLower(what[i + j]) != _toLower(where[j])) {
found = false;
break;
}
}
if (found) {
return true;
}
}
return false;
}
function _setName(uint256 tokenId, string memory name) internal {
if (bytes(drifterNames[tokenId]).length > 0) {
usedNames[drifterNames[tokenId]] = false;
}
drifterNames[tokenId] = name;
usedNames[name] = true;
emit NameSet(tokenId, name);
}
function getName(uint256 tokenId) external view returns (string memory) {
string memory name = drifterNames[tokenId];
require(bytes(name).length > 0, "No name set for this token");
return name;
}
}
文件 14 的 45:ERC1155.sol
pragma solidity ^0.8.0;
import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./extensions/IERC1155MetadataURI.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/introspection/ERC165.sol";
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
using Address for address;
mapping(uint256 => mapping(address => uint256)) private _balances;
mapping(address => mapping(address => bool)) private _operatorApprovals;
string private _uri;
constructor(string memory uri_) {
_setURI(uri_);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
function uri(uint256) public view virtual override returns (string memory) {
return _uri;
}
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
require(account != address(0), "ERC1155: address zero is not a valid owner");
return _balances[id][account];
}
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
override
returns (uint256[] memory)
{
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeTransferFrom(from, to, id, amount, data);
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
function _safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
emit TransferSingle(operator, from, to, id, amount);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
_balances[id][to] += amount;
emit TransferSingle(operator, address(0), to, id, amount);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
function _mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
emit TransferSingle(operator, from, address(0), id, amount);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
function _burnBatch(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
for (uint256 i = 0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC1155: setting approval status for self");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
function _afterTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](1);
array[0] = element;
return array;
}
}
文件 15 的 45:ERC1155C.sol
pragma solidity ^0.8.4;
import "../utils/AutomaticValidatorTransferApproval.sol";
import "../utils/CreatorTokenBase.sol";
import "../token/erc1155/ERC1155OpenZeppelin.sol";
import {TOKEN_TYPE_ERC1155} from "@limitbreak/permit-c/src/Constants.sol";
abstract contract ERC1155C is ERC1155OpenZeppelin, CreatorTokenBase, AutomaticValidatorTransferApproval {
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool isApproved) {
isApproved = super.isApprovedForAll(owner, operator);
if (!isApproved) {
if (autoApproveTransfersFromValidator) {
isApproved = operator == address(getTransferValidator());
}
}
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(ICreatorToken).interfaceId ||
interfaceId == type(ICreatorTokenLegacy).interfaceId ||
super.supportsInterface(interfaceId);
}
function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) {
functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256,uint256)"));
isViewFunction = false;
}
function _beforeTokenTransfer(
address ,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateBeforeTransfer(from, to, ids[i], amounts[i]);
unchecked {
++i;
}
}
}
function _afterTokenTransfer(
address ,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateAfterTransfer(from, to, ids[i], amounts[i]);
unchecked {
++i;
}
}
}
function _tokenType() internal pure override returns(uint16) {
return uint16(TOKEN_TYPE_ERC1155);
}
}
abstract contract ERC1155CInitializable is ERC1155OpenZeppelinInitializable, CreatorTokenBase, AutomaticValidatorTransferApproval {
function initializeERC1155(string memory uri_) public override {
super.initializeERC1155(uri_);
_emitDefaultTransferValidator();
_registerTokenType(getTransferValidator());
}
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool isApproved) {
isApproved = super.isApprovedForAll(owner, operator);
if (!isApproved) {
if (autoApproveTransfersFromValidator) {
isApproved = operator == address(getTransferValidator());
}
}
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(ICreatorToken).interfaceId ||
interfaceId == type(ICreatorTokenLegacy).interfaceId ||
super.supportsInterface(interfaceId);
}
function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) {
functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256,uint256)"));
isViewFunction = false;
}
function _beforeTokenTransfer(
address ,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateBeforeTransfer(from, to, ids[i], amounts[i]);
unchecked {
++i;
}
}
}
function _afterTokenTransfer(
address ,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateAfterTransfer(from, to, ids[i], amounts[i]);
unchecked {
++i;
}
}
}
function _tokenType() internal pure override returns(uint16) {
return uint16(TOKEN_TYPE_ERC1155);
}
}
文件 16 的 45:ERC1155Holder.sol
pragma solidity ^0.8.0;
import "./ERC1155Receiver.sol";
contract ERC1155Holder is ERC1155Receiver {
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
}
文件 17 的 45:ERC1155OpenZeppelin.sol
pragma solidity ^0.8.4;
import "../../access/OwnablePermissions.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
abstract contract ERC1155OpenZeppelinBase is ERC1155 {
}
abstract contract ERC1155OpenZeppelin is ERC1155OpenZeppelinBase {
constructor(string memory uri_) ERC1155(uri_) {}
}
abstract contract ERC1155OpenZeppelinInitializable is OwnablePermissions, ERC1155OpenZeppelinBase {
error ERC1155OpenZeppelinInitializable__AlreadyInitializedERC1155();
bool private _erc1155Initialized;
function initializeERC1155(string memory uri_) public virtual {
_requireCallerIsContractOwner();
if(_erc1155Initialized) {
revert ERC1155OpenZeppelinInitializable__AlreadyInitializedERC1155();
}
_erc1155Initialized = true;
_setURI(uri_);
}
}
文件 18 的 45:ERC1155Receiver.sol
pragma solidity ^0.8.0;
import "../IERC1155Receiver.sol";
import "../../../utils/introspection/ERC165.sol";
abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
}
}
文件 19 的 45: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;
}
}
文件 20 的 45:ERC2981.sol
pragma solidity ^0.8.0;
import "../../interfaces/IERC2981.sol";
import "../../utils/introspection/ERC165.sol";
abstract contract ERC2981 is IERC2981, ERC165 {
struct RoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
RoyaltyInfo private _defaultRoyaltyInfo;
mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];
if (royalty.receiver == address(0)) {
royalty = _defaultRoyaltyInfo;
}
uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();
return (royalty.receiver, royaltyAmount);
}
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: invalid receiver");
_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
function _deleteDefaultRoyalty() internal virtual {
delete _defaultRoyaltyInfo;
}
function _setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: Invalid parameters");
_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
delete _tokenRoyaltyInfo[tokenId];
}
}
文件 21 的 45: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: address zero is not a valid owner");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
address owner = _ownerOf(tokenId);
require(owner != address(0), "ERC721: invalid token ID");
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);
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 token owner or approved for all"
);
_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 {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or 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: caller is not token owner or 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 _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 = ERC721.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);
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, 1);
require(!_exists(tokenId), "ERC721: token already minted");
unchecked {
_balances[to] += 1;
}
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
_afterTokenTransfer(address(0), to, tokenId, 1);
}
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId, 1);
owner = ERC721.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 {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId, 1);
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
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(ERC721.ownerOf(tokenId), to, tokenId);
}
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC721: approve to caller");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
function _requireMinted(uint256 tokenId) internal view virtual {
require(_exists(tokenId), "ERC721: invalid token ID");
}
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 firstTokenId,
uint256 batchSize
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 firstTokenId,
uint256 batchSize
) internal virtual {}
function __unsafe_increaseBalance(address account, uint256 amount) internal {
_balances[account] += amount;
}
}
文件 22 的 45:ERC721C.sol
pragma solidity ^0.8.4;
import "../utils/AutomaticValidatorTransferApproval.sol";
import "../utils/CreatorTokenBase.sol";
import "../token/erc721/ERC721OpenZeppelin.sol";
import "../interfaces/ITransferValidatorSetTokenType.sol";
import {TOKEN_TYPE_ERC721} from "@limitbreak/permit-c/src/Constants.sol";
abstract contract ERC721C is ERC721OpenZeppelin, CreatorTokenBase, AutomaticValidatorTransferApproval {
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool isApproved) {
isApproved = super.isApprovedForAll(owner, operator);
if (!isApproved) {
if (autoApproveTransfersFromValidator) {
isApproved = operator == address(getTransferValidator());
}
}
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(ICreatorToken).interfaceId ||
interfaceId == type(ICreatorTokenLegacy).interfaceId ||
super.supportsInterface(interfaceId);
}
function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) {
functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256)"));
isViewFunction = true;
}
function _beforeTokenTransfer(
address from,
address to,
uint256 firstTokenId,
uint256 batchSize) internal virtual override {
for (uint256 i = 0; i < batchSize;) {
_validateBeforeTransfer(from, to, firstTokenId + i);
unchecked {
++i;
}
}
}
function _afterTokenTransfer(
address from,
address to,
uint256 firstTokenId,
uint256 batchSize) internal virtual override {
for (uint256 i = 0; i < batchSize;) {
_validateAfterTransfer(from, to, firstTokenId + i);
unchecked {
++i;
}
}
}
function _tokenType() internal pure override returns(uint16) {
return uint16(TOKEN_TYPE_ERC721);
}
}
abstract contract ERC721CInitializable is ERC721OpenZeppelinInitializable, CreatorTokenBase, AutomaticValidatorTransferApproval {
function initializeERC721(string memory name_, string memory symbol_) public override {
super.initializeERC721(name_, symbol_);
_emitDefaultTransferValidator();
_registerTokenType(getTransferValidator());
}
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool isApproved) {
isApproved = super.isApprovedForAll(owner, operator);
if (!isApproved) {
if (autoApproveTransfersFromValidator) {
isApproved = operator == address(getTransferValidator());
}
}
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(ICreatorToken).interfaceId ||
interfaceId == type(ICreatorTokenLegacy).interfaceId ||
super.supportsInterface(interfaceId);
}
function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) {
functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256)"));
isViewFunction = true;
}
function _beforeTokenTransfer(
address from,
address to,
uint256 firstTokenId,
uint256 batchSize) internal virtual override {
for (uint256 i = 0; i < batchSize;) {
_validateBeforeTransfer(from, to, firstTokenId + i);
unchecked {
++i;
}
}
}
function _afterTokenTransfer(
address from,
address to,
uint256 firstTokenId,
uint256 batchSize) internal virtual override {
for (uint256 i = 0; i < batchSize;) {
_validateAfterTransfer(from, to, firstTokenId + i);
unchecked {
++i;
}
}
}
function _tokenType() internal pure override returns(uint16) {
return uint16(TOKEN_TYPE_ERC721);
}
}
文件 23 的 45:ERC721OpenZeppelin.sol
pragma solidity ^0.8.4;
import "../../access/OwnablePermissions.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
abstract contract ERC721OpenZeppelinBase is ERC721 {
string internal _contractName;
string internal _contractSymbol;
function name() public view virtual override returns (string memory) {
return _contractName;
}
function symbol() public view virtual override returns (string memory) {
return _contractSymbol;
}
function _setNameAndSymbol(string memory name_, string memory symbol_) internal {
_contractName = name_;
_contractSymbol = symbol_;
}
}
abstract contract ERC721OpenZeppelin is ERC721OpenZeppelinBase {
constructor(string memory name_, string memory symbol_) ERC721("", "") {
_setNameAndSymbol(name_, symbol_);
}
}
abstract contract ERC721OpenZeppelinInitializable is OwnablePermissions, ERC721OpenZeppelinBase {
error ERC721OpenZeppelinInitializable__AlreadyInitializedERC721();
bool private _erc721Initialized;
function initializeERC721(string memory name_, string memory symbol_) public virtual {
_requireCallerIsContractOwner();
if(_erc721Initialized) {
revert ERC721OpenZeppelinInitializable__AlreadyInitializedERC721();
}
_erc721Initialized = true;
_setNameAndSymbol(name_, symbol_);
}
}
文件 24 的 45:GEAR.sol
pragma solidity ^0.8.0;
import "@limitbreak/creator-token-standards/src/erc1155c/ERC1155C.sol";
import "@limitbreak/creator-token-standards/src/access/OwnableBasic.sol";
import "./SplitRoyalties.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./Drifter.sol";
import "./GEARMetadata.sol";
contract GEAR is ERC1155C, SplitRoyalties, GEARMetadata, OwnableBasic {
using Strings for uint256;
uint96 private constant ROYALTY_FEE_NUMERATOR = 500;
uint256 public minted;
string public baseURI;
address[] public GEAR_MINTER_ADDRESSES;
address public DRIFTER_ADDRESS;
mapping(uint256 => uint256) public tokenMintCount;
modifier onlyGearMinters() {
bool isMinter = false;
for (uint256 i = 0; i < GEAR_MINTER_ADDRESSES.length; i++) {
if (GEAR_MINTER_ADDRESSES[i] == msg.sender) {
isMinter = true;
break;
}
}
require(isMinter, "Caller is not a Gear minter");
_;
}
constructor(string memory _baseURI, address _royaltyReceiver) ERC1155OpenZeppelin(_baseURI) SplitRoyalties(_royaltyReceiver, ROYALTY_FEE_NUMERATOR) {
baseURI = _baseURI;
}
function name() public pure returns (string memory) {
return "Drifter G.E.A.R.";
}
function symbol() public pure returns (string memory) {
return "DRIFTERGEAR";
}
function setBaseURI(string memory _baseURI) external onlyOwner {
baseURI = _baseURI;
}
function addGearMinter(address minterAddress) external onlyOwner {
require(minterAddress != address(0), "Invalid minter address");
for (uint256 i = 0; i < GEAR_MINTER_ADDRESSES.length; i++) {
if (GEAR_MINTER_ADDRESSES[i] == minterAddress) {
return;
}
}
GEAR_MINTER_ADDRESSES.push(minterAddress);
}
function removeGearMinter(address minterAddress) external onlyOwner {
for (uint256 i = 0; i < GEAR_MINTER_ADDRESSES.length; i++) {
if (GEAR_MINTER_ADDRESSES[i] == minterAddress) {
GEAR_MINTER_ADDRESSES[i] = GEAR_MINTER_ADDRESSES[GEAR_MINTER_ADDRESSES.length - 1];
GEAR_MINTER_ADDRESSES.pop();
break;
}
}
}
function setDrifterAddress(address drifterAddress) external onlyOwner {
DRIFTER_ADDRESS = drifterAddress;
}
function mint(address to, uint256 tokenId, uint256 amount) external onlyGearMinters {
_mint(to, tokenId, amount, "");
minted += amount;
tokenMintCount[tokenId] += amount;
}
function setTokenSplitRoyalty(uint256 tokenId, address[] memory recipients) external onlyOwner {
setTokenRoyalty(tokenId, ROYALTY_FEE_NUMERATOR, recipients);
}
function setTokenSplitRoyaltyBatch(uint256[] memory tokenIds, address[] memory recipients) external onlyOwner {
setTokenRoyaltyBatch(tokenIds, ROYALTY_FEE_NUMERATOR, recipients);
}
function totalSupply() public view returns (uint256) {
return minted;
}
function uri(uint256 tokenId) public view virtual override returns (string memory) {
return string(abi.encodePacked(baseURI, tokenId.toString()));
}
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
if (operator == DRIFTER_ADDRESS) {
return true;
}
return super.isApprovedForAll(account, operator);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155C, SplitRoyalties) returns (bool) {
return super.supportsInterface(interfaceId);
}
function isNonNFTAsset(uint256 assetId) public pure returns (bool) {
return isNonNFT(assetId);
}
function getTotalAssets() public view returns (uint256) {
return totalAssets;
}
function getTotalNFTAssets() public view returns (uint256) {
return totalNFTAssets;
}
function createCategoryBatch(string[] memory _categories) external onlyOwner {
_createCategoryBatch(_categories);
}
function createCategory(string memory category) external onlyOwner {
_createCategory(category);
}
function createDrifterAssetBatch(
uint256[] memory assetIds,
string[] memory keys,
string[] memory names,
string[] memory _categories,
string[] memory genders,
Rarity[] memory rarities,
bool[] memory inDnaCardPacks
) external onlyOwner {
_createDrifterAssetBatch(assetIds, keys, names, _categories, genders, rarities, inDnaCardPacks);
}
function createDrifterAsset(
uint256 assetId,
string memory key,
string memory _name,
string memory category,
string memory gender,
Rarity rarity,
bool inDnaCardPack
) external onlyOwner {
_createDrifterAsset(assetId, key, _name, category, gender, rarity, inDnaCardPack);
}
function editDrifterAsset(
uint256 assetId,
string memory key,
string memory _name,
string memory category,
string memory gender,
Rarity rarity,
bool inDnaCardPack
) external onlyOwner {
_editDrifterAsset(assetId, key, _name, category, gender, rarity, inDnaCardPack);
}
function getCategory(uint256 index) external view returns (string memory) {
return getCategoryByIndex(index);
}
function getAssetCategory(uint256 assetId) external view returns (string memory) {
return getDrifterAssetCategory(assetId);
}
function getAssetRarity(uint256 assetId) external view returns (Rarity) {
return getDrifterAssetRarity(assetId);
}
receive() external payable {
revert("Direct ETH transfers not allowed");
}
}
文件 25 的 45:GEARMetadata.sol
pragma solidity ^0.8.4;
abstract contract GEARMetadata {
uint256 public constant NON_NFT_BIT = 1 << 24;
mapping(uint256 => DrifterAssetInfo) public assetInfo;
enum Rarity {
COMMON,
UNCOMMON,
RARE,
EPIC,
LEGENDARY,
MYTHIC
}
string[] public categories;
struct DrifterAssetInfo {
string key;
string name;
string category;
string gender;
Rarity rarity;
bool inDnaCardPack;
}
mapping(Rarity => uint256[]) public rarityAssetIds;
mapping(Rarity => uint256[]) public rarityNFTAssetIds;
mapping(string => uint256[]) public categoryAssetIds;
mapping(string => uint256[]) public categoryNFTAssetIds;
uint256 public totalAssets;
uint256 public totalNFTAssets;
function isNonNFT(uint256 assetId) public pure returns (bool) {
return assetId & NON_NFT_BIT > 0;
}
function _createCategoryBatch(string[] memory _categories) internal {
for (uint256 i = 0; i < _categories.length; i++) {
_createCategory(_categories[i]);
}
}
function _createCategory(string memory category) internal {
require(bytes(category).length > 0, "Category cannot be empty");
require(bytes(category)[0] != " ", "Category cannot start with a space");
require(bytes(category)[bytes(category).length - 1] != " ", "Category cannot end with a space");
for (uint256 i = 0; i < categories.length; i++) {
if (keccak256(abi.encodePacked(categories[i])) == keccak256(abi.encodePacked(category))) {
revert("Category already exists");
}
}
categories.push(category);
}
function _createDrifterAssetBatch(
uint256[] memory assetIds,
string[] memory keys,
string[] memory names,
string[] memory _categories,
string[] memory genders,
Rarity[] memory rarities,
bool[] memory inDnaCardPacks
) internal {
require(
assetIds.length == keys.length &&
assetIds.length == names.length &&
assetIds.length == _categories.length &&
assetIds.length == genders.length &&
assetIds.length == rarities.length &&
assetIds.length == inDnaCardPacks.length,
"Invalid array lengths"
);
for (uint256 i = 0; i < assetIds.length; i++) {
_createDrifterAsset(assetIds[i], keys[i], names[i], _categories[i], genders[i], rarities[i], inDnaCardPacks[i]);
}
}
function _createDrifterAsset(
uint256 assetId,
string memory key,
string memory name,
string memory category,
string memory gender,
Rarity rarity,
bool inDnaCardPack
) internal {
require(bytes(assetInfo[assetId].key).length == 0, "Drifter asset already exists for this asset ID");
internalEditDrifterAsset(assetId, key, name, category, gender, rarity, inDnaCardPack);
internalAddAssetIdToRarity(assetId, rarity);
internalAddAssetIdToCategory(assetId, category);
if (!isNonNFT(assetId)) {
totalNFTAssets++;
}
totalAssets++;
}
function _editDrifterAsset(
uint256 assetId,
string memory key,
string memory name,
string memory category,
string memory gender,
Rarity rarity,
bool inDnaCardPack
) internal {
require(bytes(assetInfo[assetId].key).length > 0, "Drifter asset does not exist for this asset ID");
bool changedRarity = false;
if (assetInfo[assetId].rarity != rarity) {
changedRarity = true;
}
string memory oldCategory = assetInfo[assetId].category;
Rarity oldRarity = assetInfo[assetId].rarity;
internalEditDrifterAsset(assetId, key, name, category, gender, rarity, inDnaCardPack);
if (changedRarity) {
internalRemoveAssetIdFromRarity(assetId, oldRarity);
internalAddAssetIdToRarity(assetId, rarity);
}
if (keccak256(abi.encodePacked(oldCategory)) != keccak256(abi.encodePacked(category)) && bytes(oldCategory).length > 0) {
internalRemoveAssetIdFromCategory(assetId, oldCategory);
internalAddAssetIdToCategory(assetId, category);
}
}
function internalEditDrifterAsset(
uint256 assetId,
string memory key,
string memory name,
string memory category,
string memory gender,
Rarity rarity,
bool inDnaCardPack
) internal {
require(bytes(name).length > 0, "Name cannot be empty");
require(bytes(category).length > 0, "Category cannot be empty");
bool categoryExists = false;
for (uint256 i = 0; i < categories.length; i++) {
if (keccak256(abi.encodePacked(categories[i])) == keccak256(abi.encodePacked(category))) {
categoryExists = true;
}
}
require(categoryExists, "Category does not exist");
require(rarity >= Rarity.COMMON && rarity <= Rarity.MYTHIC, "Invalid rarity");
assetInfo[assetId] = DrifterAssetInfo(key, name, category, gender, rarity, inDnaCardPack);
}
function internalAddAssetIdToCategory(uint256 assetId, string memory category) internal {
categoryAssetIds[category].push(assetId);
if (!isNonNFT(assetId)) {
categoryNFTAssetIds[category].push(assetId);
}
}
function internalAddAssetIdToRarity(uint256 assetId, Rarity rarity) internal {
rarityAssetIds[rarity].push(assetId);
if (!isNonNFT(assetId)) {
rarityNFTAssetIds[rarity].push(assetId);
}
}
function findItemInArray(uint256[] memory array, uint256 item) internal pure returns (bool found, uint256 index) {
for (uint256 i = 0; i < array.length; i++) {
if (array[i] == item) {
index = i;
found = true;
break;
}
}
return (found, index);
}
function internalRemoveAssetIdFromCategory(uint256 assetId, string memory category) internal {
(bool found, uint256 index) = findItemInArray(categoryAssetIds[category], assetId);
require(found, "Asset ID not found in category");
categoryAssetIds[category][index] = categoryAssetIds[category][categoryAssetIds[category].length - 1];
categoryAssetIds[category].pop();
if (!isNonNFT(assetId)) {
(bool _found, uint256 _index) = findItemInArray(categoryNFTAssetIds[category], assetId);
require(_found, "Asset ID not found in category NFT asset IDs");
categoryNFTAssetIds[category][_index] = categoryNFTAssetIds[category][categoryNFTAssetIds[category].length - 1];
categoryNFTAssetIds[category].pop();
}
}
function internalRemoveAssetIdFromRarity(uint256 assetId, Rarity rarity) internal {
(bool found, uint256 index) = findItemInArray(rarityAssetIds[rarity], assetId);
require(found, "Asset ID not found in rarity");
rarityAssetIds[rarity][index] = rarityAssetIds[rarity][rarityAssetIds[rarity].length - 1];
rarityAssetIds[rarity].pop();
if (!isNonNFT(assetId)) {
(bool _found, uint256 _index) = findItemInArray(rarityNFTAssetIds[rarity], assetId);
require(_found, "Asset ID not found in rarity NFT asset IDs");
rarityNFTAssetIds[rarity][_index] = rarityNFTAssetIds[rarity][rarityNFTAssetIds[rarity].length - 1];
rarityNFTAssetIds[rarity].pop();
}
}
function getRarityAssetIds(Rarity rarity) public view returns (uint256[] memory) {
return rarityAssetIds[rarity];
}
function getRarityNFTAssetIds(Rarity rarity) public view returns (uint256[] memory) {
return rarityNFTAssetIds[rarity];
}
function getCategoryAssetIds(string memory category) public view returns (uint256[] memory) {
return categoryAssetIds[category];
}
function getCategoryNFTAssetIds(string memory category) public view returns (uint256[] memory) {
return categoryNFTAssetIds[category];
}
function getCategoryAssetIdsForRarity(string memory category, Rarity rarity) public view returns (uint256[] memory) {
uint256[] memory _categoryAssetIds = new uint256[](categoryAssetIds[category].length);
uint256 index = 0;
for (uint256 i = 0; i < categoryAssetIds[category].length; i++) {
if (assetInfo[categoryAssetIds[category][i]].rarity == rarity) {
_categoryAssetIds[index] = categoryAssetIds[category][i];
index++;
}
}
assembly {
mstore(_categoryAssetIds, index)
}
return _categoryAssetIds;
}
function getCategoryNFTAssetIdsForRarity(string memory category, Rarity rarity) public view returns (uint256[] memory) {
uint256[] memory _categoryNFTAssetIds = new uint256[](categoryNFTAssetIds[category].length);
uint256 index = 0;
for (uint256 i = 0; i < categoryNFTAssetIds[category].length; i++) {
if (assetInfo[categoryNFTAssetIds[category][i]].rarity == rarity) {
_categoryNFTAssetIds[index] = categoryNFTAssetIds[category][i];
index++;
}
}
assembly {
mstore(_categoryNFTAssetIds, index)
}
return _categoryNFTAssetIds;
}
function getCategoryCount() public view returns (uint256) {
return categories.length;
}
function getCategoryByIndex(uint256 index) public view returns (string memory) {
require(index < categories.length, "Index out of bounds");
return categories[index];
}
function getDrifterAssetCategory(uint256 assetId) public view returns (string memory) {
return assetInfo[assetId].category;
}
function getDrifterAssetRarity(uint256 assetId) public view returns (Rarity) {
return assetInfo[assetId].rarity;
}
}
文件 26 的 45:ICreatorToken.sol
pragma solidity ^0.8.4;
interface ICreatorToken {
event TransferValidatorUpdated(address oldValidator, address newValidator);
function getTransferValidator() external view returns (address validator);
function setTransferValidator(address validator) external;
function getTransferValidationFunction() external view returns (bytes4 functionSignature, bool isViewFunction);
}
文件 27 的 45:ICreatorTokenLegacy.sol
pragma solidity ^0.8.4;
interface ICreatorTokenLegacy {
event TransferValidatorUpdated(address oldValidator, address newValidator);
function getTransferValidator() external view returns (address validator);
function setTransferValidator(address validator) external;
}
文件 28 的 45:IERC1155.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC1155 is IERC165 {
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address account, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
文件 29 的 45:IERC1155MetadataURI.sol
pragma solidity ^0.8.0;
import "../IERC1155.sol";
interface IERC1155MetadataURI is IERC1155 {
function uri(uint256 id) external view returns (string memory);
}
文件 30 的 45:IERC1155Receiver.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC1155Receiver is IERC165 {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
文件 31 的 45:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 32 的 45: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);
}
文件 33 的 45:IERC2981.sol
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165.sol";
interface IERC2981 is IERC165 {
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}
文件 34 的 45: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);
}
文件 35 的 45: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);
}
文件 36 的 45:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 37 的 45:ITransferValidator.sol
pragma solidity ^0.8.4;
interface ITransferValidator {
function applyCollectionTransferPolicy(address caller, address from, address to) external view;
function validateTransfer(address caller, address from, address to) external view;
function validateTransfer(address caller, address from, address to, uint256 tokenId) external view;
function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external;
function beforeAuthorizedTransfer(address operator, address token, uint256 tokenId) external;
function afterAuthorizedTransfer(address token, uint256 tokenId) external;
function beforeAuthorizedTransfer(address operator, address token) external;
function afterAuthorizedTransfer(address token) external;
function beforeAuthorizedTransfer(address token, uint256 tokenId) external;
function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external;
function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external;
}
文件 38 的 45:ITransferValidatorSetTokenType.sol
pragma solidity ^0.8.4;
interface ITransferValidatorSetTokenType {
function setTokenTypeOfCollection(address collection, uint16 tokenType) external;
}
文件 39 的 45: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);
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 * 8) < value ? 1 : 0);
}
}
}
文件 40 的 45: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);
}
}
文件 41 的 45:OwnableBasic.sol
pragma solidity ^0.8.4;
import "./OwnablePermissions.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
abstract contract OwnableBasic is OwnablePermissions, Ownable {
function _requireCallerIsContractOwner() internal view virtual override {
_checkOwner();
}
}
文件 42 的 45:OwnablePermissions.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Context.sol";
abstract contract OwnablePermissions is Context {
function _requireCallerIsContractOwner() internal view virtual;
}
文件 43 的 45:SplitRoyalties.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/interfaces/IERC2981.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
abstract contract SplitRoyalties is IERC2981, ERC165 {
uint256 public constant FEE_DENOMINATOR = 10_000;
address private _defaultRoyaltyReceiver;
uint96 private _defaultRoyaltyFeeNumerator;
struct TokenRoyaltyInfo {
uint96 feeNumerator;
address[] recipients;
bool initialized;
}
mapping(uint256 => TokenRoyaltyInfo) private _tokenRoyalties;
event DefaultRoyaltySet(address receiver, uint96 feeNumerator);
event TokenRoyaltySet(uint256 tokenId, uint96 feeNumerator, address[] recipients);
event TokenRoyaltyRecipientsUpdated(uint256 tokenId, address[] recipients);
error SplitRoyalties__RoyaltyFeeWillExceedSalePrice();
error SplitRoyalties__InvalidRoyaltyReceiver();
error SplitRoyalties__NoRecipientsProvided();
error SplitRoyalties__TokenRoyaltyNotInitialized();
constructor(address defaultRoyaltyReceiver, uint96 defaultRoyaltyFeeNumerator) {
_setDefaultRoyalty(defaultRoyaltyReceiver, defaultRoyaltyFeeNumerator);
}
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal {
if (feeNumerator > FEE_DENOMINATOR) {
revert SplitRoyalties__RoyaltyFeeWillExceedSalePrice();
}
if (receiver == address(0)) {
revert SplitRoyalties__InvalidRoyaltyReceiver();
}
_defaultRoyaltyReceiver = receiver;
_defaultRoyaltyFeeNumerator = feeNumerator;
emit DefaultRoyaltySet(receiver, feeNumerator);
}
function _setTokenRoyalty(uint256 tokenId, uint96 feeNumerator, address[] memory recipients) internal {
if (feeNumerator > FEE_DENOMINATOR) {
revert SplitRoyalties__RoyaltyFeeWillExceedSalePrice();
}
if (recipients.length == 0) {
revert SplitRoyalties__NoRecipientsProvided();
}
for (uint256 i = 0; i < recipients.length; i++) {
if (recipients[i] == address(0)) {
revert SplitRoyalties__InvalidRoyaltyReceiver();
}
}
_tokenRoyalties[tokenId] = TokenRoyaltyInfo({feeNumerator: feeNumerator, recipients: recipients, initialized: true});
emit TokenRoyaltySet(tokenId, feeNumerator, recipients);
}
function royaltyInfo(uint256 tokenId, uint256 salePrice) external view override returns (address receiver, uint256 royaltyAmount) {
TokenRoyaltyInfo storage info = _tokenRoyalties[tokenId];
if (info.initialized) {
uint256 royaltyFee = (salePrice * info.feeNumerator) / FEE_DENOMINATOR;
return (info.recipients.length > 0 ? info.recipients[0] : _defaultRoyaltyReceiver, royaltyFee);
} else {
return (_defaultRoyaltyReceiver, (salePrice * _defaultRoyaltyFeeNumerator) / FEE_DENOMINATOR);
}
}
function calculateRoyaltyPerRecipient(uint256 tokenId, uint256 salePrice) public view returns (address[] memory recipients, uint256[] memory amounts) {
TokenRoyaltyInfo storage info = _tokenRoyalties[tokenId];
if (info.initialized && info.recipients.length > 0) {
recipients = info.recipients;
amounts = new uint256[](recipients.length);
uint256 totalRoyalty = (salePrice * info.feeNumerator) / FEE_DENOMINATOR;
uint256 sharePerRecipient = totalRoyalty / recipients.length;
for (uint256 i = 0; i < recipients.length; i++) {
amounts[i] = sharePerRecipient;
}
} else {
recipients = new address[](1);
amounts = new uint256[](1);
recipients[0] = _defaultRoyaltyReceiver;
amounts[0] = (salePrice * _defaultRoyaltyFeeNumerator) / FEE_DENOMINATOR;
}
return (recipients, amounts);
}
function setDefaultRoyalty(address receiver, uint96 feeNumerator) internal {
_setDefaultRoyalty(receiver, feeNumerator);
}
function setTokenRoyalty(uint256 tokenId, uint96 feeNumerator, address[] memory recipients) internal {
_setTokenRoyalty(tokenId, feeNumerator, recipients);
}
function setTokenRoyaltyBatch(uint256[] memory tokenIds, uint96 feeNumerator, address[] memory recipients) internal {
for (uint256 i = 0; i < tokenIds.length; i++) {
_setTokenRoyalty(tokenIds[i], feeNumerator, recipients);
}
}
function updateTokenRoyaltyRecipients(uint256 tokenId, address[] memory recipients) internal {
TokenRoyaltyInfo storage info = _tokenRoyalties[tokenId];
if (!info.initialized) {
revert SplitRoyalties__TokenRoyaltyNotInitialized();
}
if (recipients.length == 0) {
revert SplitRoyalties__NoRecipientsProvided();
}
for (uint256 i = 0; i < recipients.length; i++) {
if (recipients[i] == address(0)) {
revert SplitRoyalties__InvalidRoyaltyReceiver();
}
}
info.recipients = recipients;
emit TokenRoyaltyRecipientsUpdated(tokenId, recipients);
}
function addTokenRoyaltyRecipient(uint256 tokenId, address recipient) internal {
TokenRoyaltyInfo storage info = _tokenRoyalties[tokenId];
if (!info.initialized) {
revert SplitRoyalties__TokenRoyaltyNotInitialized();
}
if (recipient == address(0)) {
revert SplitRoyalties__InvalidRoyaltyReceiver();
}
for (uint256 i = 0; i < info.recipients.length; i++) {
if (info.recipients[i] == recipient) {
return;
}
}
info.recipients.push(recipient);
emit TokenRoyaltyRecipientsUpdated(tokenId, info.recipients);
}
function removeTokenRoyaltyRecipient(uint256 tokenId, address recipient) internal {
TokenRoyaltyInfo storage info = _tokenRoyalties[tokenId];
if (!info.initialized) {
revert SplitRoyalties__TokenRoyaltyNotInitialized();
}
if (info.recipients.length <= 1) {
revert SplitRoyalties__NoRecipientsProvided();
}
bool found = false;
for (uint256 i = 0; i < info.recipients.length; i++) {
if (info.recipients[i] == recipient) {
info.recipients[i] = info.recipients[info.recipients.length - 1];
info.recipients.pop();
found = true;
break;
}
}
if (found) {
emit TokenRoyaltyRecipientsUpdated(tokenId, info.recipients);
}
}
function resetTokenRoyalty(uint256 tokenId) internal {
delete _tokenRoyalties[tokenId];
}
function resetTokenRoyaltyBatch(uint256[] memory tokenIds) internal {
for (uint256 i = 0; i < tokenIds.length; i++) {
delete _tokenRoyalties[tokenIds[i]];
}
}
function getDefaultRoyaltyInfo() external view returns (address receiver, uint256 feeNumerator) {
return (_defaultRoyaltyReceiver, _defaultRoyaltyFeeNumerator);
}
function getTokenRoyaltyInfo(uint256 tokenId) external view returns (uint256 feeNumerator, address[] memory recipients, bool initialized) {
TokenRoyaltyInfo storage info = _tokenRoyalties[tokenId];
return (info.feeNumerator, info.recipients, info.initialized);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
}
文件 44 的 45:Strings.sol
pragma solidity ^0.8.0;
import "./math/Math.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 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);
}
}
文件 45 的 45:TransferValidation.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Context.sol";
abstract contract TransferValidation is Context {
error ShouldNotMintToBurnAddress();
function _validateBeforeTransfer(address from, address to, uint256 tokenId) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_preValidateMint(_msgSender(), to, tokenId, msg.value);
} else if(toZeroAddress) {
_preValidateBurn(_msgSender(), from, tokenId, msg.value);
} else {
_preValidateTransfer(_msgSender(), from, to, tokenId, msg.value);
}
}
function _validateAfterTransfer(address from, address to, uint256 tokenId) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_postValidateMint(_msgSender(), to, tokenId, msg.value);
} else if(toZeroAddress) {
_postValidateBurn(_msgSender(), from, tokenId, msg.value);
} else {
_postValidateTransfer(_msgSender(), from, to, tokenId, msg.value);
}
}
function _preValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {}
function _postValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {}
function _preValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {}
function _postValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {}
function _preValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value) internal virtual {}
function _postValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value) internal virtual {}
function _validateBeforeTransfer(address from, address to, uint256 tokenId, uint256 amount) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_preValidateMint(_msgSender(), to, tokenId, amount, msg.value);
} else if(toZeroAddress) {
_preValidateBurn(_msgSender(), from, tokenId, amount, msg.value);
} else {
_preValidateTransfer(_msgSender(), from, to, tokenId, amount, msg.value);
}
}
function _validateAfterTransfer(address from, address to, uint256 tokenId, uint256 amount) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_postValidateMint(_msgSender(), to, tokenId, amount, msg.value);
} else if(toZeroAddress) {
_postValidateBurn(_msgSender(), from, tokenId, amount, msg.value);
} else {
_postValidateTransfer(_msgSender(), from, to, tokenId, amount, msg.value);
}
}
function _preValidateMint(address caller, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
function _postValidateMint(address caller, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
function _preValidateBurn(address caller, address from, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
function _postValidateBurn(address caller, address from, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
function _preValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
function _postValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
}
{
"compilationTarget": {
"contracts/DNACard.sol": "DNACard"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"royaltyReceiver_","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CreatorTokenBase__InvalidTransferValidatorContract","type":"error"},{"inputs":[],"name":"ShouldNotMintToBurnAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"autoApproved","type":"bool"}],"name":"AutomaticApprovalOfTransferValidatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"harvestedGearIds","type":"uint256[]"}],"name":"DNACardHarvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"gearIds","type":"uint256[]"}],"name":"DNACardRevealed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"DefaultRoyaltySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"TokenRoyaltySet","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":"oldValidator","type":"address"},{"indexed":false,"internalType":"address","name":"newValidator","type":"address"}],"name":"TransferValidatorUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_TRANSFER_VALIDATOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"DNA_CARD_MINTER_ADDRESSES","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LARGE_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MEDIUM_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROYALTY_FEE_NUMERATOR","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SELECTION_TIME_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SMALL_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minterAddress","type":"address"}],"name":"addDnaCardMinter","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":[],"name":"autoApproveTransfersFromValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"cardSizes","outputs":[{"internalType":"enum DNACardLib.CardSize","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"cardSkinSupplies","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"cardSkins","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dnaCardRevealContract","outputs":[{"internalType":"contract DNACardReveal","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getCardSize","outputs":[{"internalType":"enum DNACardLib.CardSize","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getCardSkin","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getRemainingSelectionTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getRevealedGear","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferValidationFunction","outputs":[{"internalType":"bytes4","name":"functionSignature","type":"bytes4"},{"internalType":"bool","name":"isViewFunction","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransferValidator","outputs":[{"internalType":"address","name":"validator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256[]","name":"selectedGearIds","type":"uint256[]"}],"name":"harvestReveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"isApproved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isHarvested","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isRevealed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"largeMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mediumMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint8","name":"cardSize","type":"uint8"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minterAddress","type":"address"}],"name":"removeDnaCardMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"reveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"revealedOwners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"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":"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":"autoApprove","type":"bool"}],"name":"setAutomaticApprovalOfTransfersFromValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newBaseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setDefaultRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"dnaCardRevealAddress","type":"address"}],"name":"setDnaCardRevealContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setTokenRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transferValidator_","type":"address"}],"name":"setTransferValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"smallMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRevealed","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"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]