// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)pragmasolidity ^0.8.0;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/functionisContract(address account) internalviewreturns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in// construction, since the code is only stored at the end of the// constructor execution.uint256 size;
assembly {
size :=extcodesize(account)
}
return size >0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable 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");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(address(this).balance>= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytesmemory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/functionverifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalpurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
Contract Source Code
File 2 of 17: AngryApeArmyEvolutionCollection.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.4;import"./ERC721ABurnable.sol";
import"./Royalty.sol";
import"./IContractURI.sol";
import"@openzeppelin/contracts/access/Ownable.sol";
import"@openzeppelin/contracts/utils/Strings.sol";
import"@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
contractAngryApeArmyEvolutionCollectionisERC721ABurnable, Royalty{
// UtilsusingECDSAforbytes32;
usingStringsforuint256;
// Sale state variablesenumSaleStates {
NOT_STARTED,
FREE_MINT,
FREE_MINT_PAUSED,
PRE_SALE,
PRE_SALE_PAUSED,
SALE,
SALE_PAUSED,
ENDED
}
SaleStates private _saleState;
// OG Ape holders
IERC721 private _aaaContract;
mapping(uint256=>uint256) private _aaaDataStore;
// Whitelistbytes32public merkleRoot;
mapping(address=>bool) public whitelistStore;
// Constantsuint256publicconstant PRE_SALE_PRICE =0.2ether;
uint256publicconstant SALE_PRICE =0.4ether;
uint32publicconstant MAX_SUPPLY =10000;
uint32publicconstant MAX_BATCH_MINT =20;
// Reserveduint32public reserved =400;
// ERC721 Metadatastringprivate _baseURI_ ="https://aaa-evolution-api-h5pd2zuvza-uc.a.run.app/";
// ECDSAaddressprivate _signer;
mapping(string=>bool) private _isNonceUsed;
// EventseventSetBaseURI(string _baseURI_);
eventFreeMintBegins();
eventPreSaleBegins();
eventSaleBegins();
eventSaleEnds();
addresspublic aaaWithdrawal;
addresspublic netvrkWithdrawal;
constructor(address signer_,
address aaaContract_,
address royaltyReceiver_
)
ERC721ABurnable("Angry Ape Army Evolution Collection",
"AAAEVO",
MAX_BATCH_MINT
)
Royalty(royaltyReceiver_, 750) // 7.50%{
_aaaContract = IERC721(aaaContract_);
_signer = signer_;
aaaWithdrawal =0x6ab71C2025442B694C8585aCe2fc06D877469D30;
netvrkWithdrawal =0x901FC05c4a4bC027a8979089D716b6793052Cc16;
}
receive() externalpayable{}
// Signature verfificationmodifieronlySignedTx(uint256 quantity_,
stringmemory nonce_,
bytescalldata signature_
) {
require(!_isNonceUsed[nonce_], "Nonce already used");
require(
keccak256(abi.encodePacked(msg.sender, quantity_, nonce_))
.toEthSignedMessageHash()
.recover(signature_) == _signer,
"Signature does not correspond"
);
_isNonceUsed[nonce_] =true;
_;
}
functionsetSignerAddress(address signerAddress_) externalonlyOwner{
_signer = signerAddress_;
}
// Free MintfunctionfreeMint(uint256[] calldata freeMintTokens_,
uint256[] calldata preSaleTokens_,
stringmemory nonce_,
bytescalldata signature_
)
externalpayableonlySignedTx(
freeMintTokens_.length + preSaleTokens_.length,
nonce_,
signature_
)
{
uint256 quantity_ = freeMintTokens_.length+ preSaleTokens_.length;
require(_saleState == SaleStates.FREE_MINT, "Free mint not active");
require(quantity_ >0, "You must mint at least 1");
require(
quantity_ <= (MAX_SUPPLY - reserved - totalSupply()),
"Not enough supply"
);
require(
msg.value>= PRE_SALE_PRICE * preSaleTokens_.length,
"Insufficient eth to process the order"
);
require(
!usedTokenIds(freeMintTokens_, preSaleTokens_),
"Token already used"
);
for (uint256 i; i < freeMintTokens_.length; i++) {
require(
msg.sender== _aaaContract.ownerOf(freeMintTokens_[i]),
"Token not owned"
);
}
for (uint256 i; i < preSaleTokens_.length; i++) {
require(
msg.sender== _aaaContract.ownerOf(preSaleTokens_[i]),
"Token not owned"
);
}
setUsedTokenIds(freeMintTokens_, preSaleTokens_);
_safeMint(msg.sender, quantity_);
}
// Pre Sale MintfunctionpreSaleMint(bytes32[] calldata merkleProof_,
stringmemory nonce_,
bytescalldata signature_
) externalpayableonlySignedTx(1, nonce_, signature_) {
require(_saleState == SaleStates.PRE_SALE, "Pre sale not active");
require(!whitelistStore[msg.sender], "Whitelist used");
require(
1<= (MAX_SUPPLY - reserved - totalSupply()),
"Not enough supply"
);
require(msg.value>= PRE_SALE_PRICE, "Insufficient eth to process the order");
require(
MerkleProof.verify(
merkleProof_,
merkleRoot,
keccak256(abi.encodePacked(msg.sender))
),
"Proof failed"
);
whitelistStore[msg.sender] =true;
_safeMint(msg.sender, 1);
}
// Sale Mintfunctionmint(uint8 quantity_,
stringmemory nonce_,
bytescalldata signature_
) externalpayableonlySignedTx(quantity_, nonce_, signature_) {
require(_saleState == SaleStates.SALE, "Sale not active");
require(quantity_ >0, "You must mint at least 1");
require(
quantity_ <= (MAX_SUPPLY - reserved - totalSupply()),
"Not enough supply"
);
require(
quantity_ <= MAX_BATCH_MINT,
"Cannot mint more than MAX_BATCH_MINT per transaction"
);
require(
(balanceOf(msg.sender) + quantity_) <= MAX_BATCH_MINT,
"Any one wallet cannot hold more than MAX_BATCH_MINT"
);
require(
msg.value>= SALE_PRICE * quantity_,
"Insufficient eth to process the order"
);
_safeMint(msg.sender, quantity_);
}
// ReservedfunctionreservedMint(address to_, uint32 quantity_) publiconlyOwner{
require(quantity_ <= reserved, "Not enough reserved supply");
require(quantity_ >0, "You must mint at least 1");
require(
quantity_ <= MAX_BATCH_MINT,
"Cannot mint more than MAX_BATCH_MINT per transaction"
);
reserved -= quantity_;
_safeMint(to_, quantity_);
}
// Burnfunctionburn(uint256 tokenId) publicvirtual{
_burn(tokenId);
}
// Sale StatefunctionsaleState() publicviewreturns (stringmemory) {
if (_saleState == SaleStates.FREE_MINT) return"FREE_MINT";
if (_saleState == SaleStates.FREE_MINT_PAUSED)
return"FREE_MINT_PAUSED";
if (_saleState == SaleStates.PRE_SALE) return"PRE_SALE";
if (_saleState == SaleStates.PRE_SALE_PAUSED) return"PRE_SALE_PAUSED";
if (_saleState == SaleStates.SALE) return"SALE";
if (_saleState == SaleStates.SALE_PAUSED) return"SALE_PAUSED";
if (_saleState == SaleStates.ENDED) return"ENDED";
return"NOT_STARTED";
}
functionstartFreeMint() externalonlyOwner{
require(
_saleState < SaleStates.FREE_MINT,
"Free mint has already started"
);
_saleState = SaleStates.FREE_MINT;
emit FreeMintBegins();
}
functionstartPreSale() externalonlyOwner{
require(_saleState >= SaleStates.FREE_MINT, "Free mint state required");
require(
_saleState < SaleStates.PRE_SALE,
"Pre-sale has already started"
);
_saleState = SaleStates.PRE_SALE;
emit PreSaleBegins();
}
functionstartSale() externalonlyOwner{
require(_saleState >= SaleStates.PRE_SALE, "Pre-sale state required");
require(_saleState < SaleStates.SALE, "Sale has already started");
_saleState = SaleStates.SALE;
emit SaleBegins();
}
functionendSale() externalonlyOwner{
require(_saleState >= SaleStates.SALE, "Sale state required");
require(_saleState < SaleStates.ENDED, "Sale has ended");
_saleState = SaleStates.ENDED;
emit SaleEnds();
}
// Pauseablefunctionpause() publiconlyOwner{
require(
!(_saleState == SaleStates.NOT_STARTED ||
_saleState == SaleStates.ENDED),
"No active sale"
);
require(
!(_saleState == SaleStates.FREE_MINT_PAUSED ||
_saleState == SaleStates.PRE_SALE_PAUSED ||
_saleState == SaleStates.SALE_PAUSED),
"Sale is paused"
);
_saleState = SaleStates(uint8(_saleState) +1);
}
functionunpause() publiconlyOwner{
require(
!(_saleState == SaleStates.NOT_STARTED ||
_saleState == SaleStates.ENDED),
"No active sale"
);
require(
!(_saleState == SaleStates.FREE_MINT ||
_saleState == SaleStates.PRE_SALE ||
_saleState == SaleStates.SALE),
"Sale is not paused"
);
_saleState = SaleStates(uint8(_saleState) -1);
}
// Contract & token metadatafunctionsetBaseURI(stringmemory _uri) publiconlyOwner{
require(
bytes(_uri)[bytes(_uri).length-1] ==bytes1("/"),
"Must set trailing slash"
);
_baseURI_ = _uri;
emit SetBaseURI(_uri);
}
functiontokenURI(uint256 tokenId)
publicviewoverridereturns (stringmemory)
{
require(_exists(tokenId), "URI query for nonexistent token");
returnstring(
abi.encodePacked(
_baseURI_,
"token/",
tokenId.toString(),
".json"
)
);
}
functioncontractURI() publicviewreturns (stringmemory) {
returnstring(abi.encodePacked(_baseURI_, "contract.json"));
}
// WhitelistfunctionsetMerkleRoot(bytes32 _merkleRoot) publiconlyOwner{
merkleRoot = _merkleRoot;
}
// WithdrawalfunctionsetAaaWithdrawal(address withdrawalAddress_) publiconlyOwner{
require(
withdrawalAddress_ !=address(0),
"Set a valid withdrawal address"
);
aaaWithdrawal = withdrawalAddress_;
}
functionsetNetvrkWithdrawal(address withdrawalAddress_) publiconlyOwner{
require(
withdrawalAddress_ !=address(0),
"Set a valid withdrawal address"
);
netvrkWithdrawal = withdrawalAddress_;
}
functionwithdrawAll() publiconlyOwner{
uint256 totalBalance =address(this).balance;
require(totalBalance >0, "Balance is zero");
uint256 aaaAmount = (totalBalance *7000) /10000; // 70.00%uint256 netvrkAmount = totalBalance - aaaAmount; // 30.00%require(
payable(aaaWithdrawal).send(aaaAmount),
"Withdrawal Failed to AAA"
);
require(
payable(netvrkWithdrawal).send(netvrkAmount),
"Withdrawal Failed to netvrk"
);
}
// UtilitiesfunctionpackBool(uint256 _packedBools,
uint256 _boolIndex,
bool _value
) publicpurereturns (uint256) {
return
_value
? _packedBools | (uint256(1) << _boolIndex)
: _packedBools &~(uint256(1) << _boolIndex);
}
functionunPackBool(uint256 _packedBools, uint256 _boolIndex)
internalpurereturns (bool)
{
return (_packedBools >> _boolIndex) &uint256(1) ==1 ? true : false;
}
functionsetUsedTokenIds(uint256[] calldata freeMints,
uint256[] calldata preSales
) public{
uint256 cRow;
uint256 cPackedBools = _aaaDataStore[0];
for (uint256 i; i < freeMints.length; i++) {
(uint256 boolRow, uint256 boolColumn) = freeMintPosition(
freeMints[i]
);
if (boolRow != cRow) {
_aaaDataStore[cRow] = cPackedBools;
cRow = boolRow;
cPackedBools = _aaaDataStore[boolRow];
}
cPackedBools = packBool(cPackedBools, boolColumn, true);
if (i +1== freeMints.length) {
_aaaDataStore[cRow] = cPackedBools;
}
}
for (uint256 i; i < preSales.length; i++) {
(uint256 boolRow, uint256 boolColumn) = preSalePosition(
preSales[i]
);
if (boolRow != cRow) {
_aaaDataStore[cRow] = cPackedBools;
cRow = boolRow;
cPackedBools = _aaaDataStore[boolRow];
}
cPackedBools = packBool(cPackedBools, boolColumn, true);
if (i +1== preSales.length) {
_aaaDataStore[cRow] = cPackedBools;
}
}
}
functionusedTokenIds(uint256[] calldata freeMints,
uint256[] calldata preSales
) privateviewreturns (bool) {
uint256 cRow;
uint256 cPackedBools = _aaaDataStore[0];
uint256 unpackedBools;
for (uint256 i; i < freeMints.length; i++) {
(uint256 boolRow, uint256 boolColumn) = freeMintPosition(
freeMints[i]
);
if (boolRow != cRow) {
if (unpackedBools >0) returntrue;
cRow = boolRow;
cPackedBools = _aaaDataStore[boolRow];
unpackedBools =0;
}
unpackedBools =
unpackedBools |
(cPackedBools & (uint256(1) << boolColumn));
if (i +1== freeMints.length) {
if (unpackedBools >0) returntrue;
}
}
for (uint256 i; i < preSales.length; i++) {
(uint256 boolRow, uint256 boolColumn) = preSalePosition(
preSales[i]
);
if (boolRow != cRow) {
if (unpackedBools >0) returntrue;
cRow = boolRow;
cPackedBools = _aaaDataStore[boolRow];
unpackedBools =0;
}
unpackedBools =
unpackedBools |
(cPackedBools & (uint256(1) << boolColumn));
if (i +1== preSales.length) {
if (unpackedBools >0) returntrue;
}
}
returnfalse;
}
functionusedTokenId(uint256 tokenId)
publicviewreturns (bool freeMintUsed, bool preSaleUsed)
{
(uint256 boolRow, uint256 boolColumn) = freeMintPosition(tokenId);
uint256 packedBools = _aaaDataStore[boolRow];
freeMintUsed = (packedBools & (uint256(1) << boolColumn)) >0
? true
: false;
preSaleUsed = (packedBools & (uint256(1) << (boolColumn +1))) >0
? true
: false;
}
functionfreeMintPosition(uint256 tokenId)
internalpurereturns (uint256 boolRow, uint256 boolColumn)
{
boolRow = (tokenId <<1) /256;
boolColumn = (tokenId <<1) %256;
}
functionpreSalePosition(uint256 tokenId)
internalpurereturns (uint256 boolRow, uint256 boolColumn)
{
(boolRow, boolColumn) = freeMintPosition(tokenId);
boolColumn++;
}
// Compulsory overridesfunctionsupportsInterface(bytes4 interfaceId)
publicviewoverride(ERC721ABurnable, Royalty)
returns (bool)
{
return
interfaceId ==type(IERC2981).interfaceId||
interfaceId ==type(IContractURI).interfaceId||super.supportsInterface(interfaceId);
}
}
Contract Source Code
File 3 of 17: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 4 of 17: ECDSA.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/cryptography/ECDSA.sol)pragmasolidity ^0.8.0;import"../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/libraryECDSA{
enumRecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function_throwError(RecoverError error) privatepure{
if (error == RecoverError.NoError) {
return; // no error: do nothing
} elseif (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} elseif (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} elseif (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} elseif (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/functiontryRecover(bytes32 hash, bytesmemory signature) internalpurereturns (address, RecoverError) {
// Check the signature length// - case 65: r,s,v signature (standard)// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._if (signature.length==65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them// currently is to use assembly.assembly {
r :=mload(add(signature, 0x20))
s :=mload(add(signature, 0x40))
v :=byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} elseif (signature.length==64) {
bytes32 r;
bytes32 vs;
// ecrecover takes the signature parameters, and the only way to get them// currently is to use assembly.assembly {
r :=mload(add(signature, 0x20))
vs :=mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/functionrecover(bytes32 hash, bytesmemory signature) internalpurereturns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/functiontryRecover(bytes32 hash,
bytes32 r,
bytes32 vs
) internalpurereturns (address, RecoverError) {
bytes32 s;
uint8 v;
assembly {
s :=and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v :=add(shr(255, vs), 27)
}
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/functionrecover(bytes32 hash,
bytes32 r,
bytes32 vs
) internalpurereturns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/functiontryRecover(bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internalpurereturns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most// signatures from current libraries generate a unique signature with an s-value in the lower half order.//// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept// these malleable signatures as well.if (uint256(s) >0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v !=27&& v !=28) {
return (address(0), RecoverError.InvalidSignatureV);
}
// If the signature is valid (and not malleable), return the signer addressaddress signer =ecrecover(hash, v, r, s);
if (signer ==address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/functionrecover(bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internalpurereturns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/functiontoEthSignedMessageHash(bytes32 hash) internalpurereturns (bytes32) {
// 32 is the length in bytes of hash,// enforced by the type signature abovereturnkeccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/functiontoEthSignedMessageHash(bytesmemory s) internalpurereturns (bytes32) {
returnkeccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/functiontoTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internalpurereturns (bytes32) {
returnkeccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
Contract Source Code
File 5 of 17: ERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)pragmasolidity ^0.8.0;import"./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 6 of 17: ERC721ABurnable.sol
// SPDX-License-Identifier: MIT// Creators: locationtba.eth, 2pmflow.eth, skarard.ethpragmasolidity 0.8.4;import"@openzeppelin/contracts/token/ERC721/IERC721.sol";
import"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import"@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import"@openzeppelin/contracts/utils/Address.sol";
import"@openzeppelin/contracts/utils/Context.sol";
import"@openzeppelin/contracts/utils/Strings.sol";
import"@openzeppelin/contracts/utils/introspection/ERC165.sol";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata and Enumerable extension. Built to optimize for lower gas during batch mints.
*
* Assumes serials are sequentially minted starting at 0 (e.g. 0, 1, 2, 3..).
*
* Supports burning to address(0x0000...dEaD).
*/abstractcontractERC721ABurnableisContext,
ERC165,
IERC721,
IERC721Metadata,
IERC721Enumerable{
usingAddressforaddress;
usingStringsforuint256;
structTokenOwnership {
address addr;
uint64 startTimestamp;
}
structAddressData {
uint128 balance;
uint128 numberMinted;
}
structIndexSupply {
uint128 currentIndex;
uint128 totalSupply;
}
IndexSupply private indexSupply;
uint256internalimmutable maxBatchSize;
// Burn Addressaddresspublicconstant BURN_ADDRESS =0x000000000000000000000000000000000000dEaD;
// Token namestringprivate _name;
// Token symbolstringprivate _symbol;
// Mapping from token ID to ownership details// An empty struct value does not necessarily mean the token is unowned. See ownershipOf implementation for details.mapping(uint256=> TokenOwnership) private _ownerships;
// Mapping owner address to address datamapping(address=> AddressData) private _addressData;
// Mapping from token ID to approved addressmapping(uint256=>address) private _tokenApprovals;
// Mapping from owner to operator approvalsmapping(address=>mapping(address=>bool)) private _operatorApprovals;
/**
* @dev
* `maxBatchSize` refers to how much a minter can mint at a time.
*/constructor(stringmemory name_,
stringmemory symbol_,
uint256 maxBatchSize_
) {
require(
maxBatchSize_ >0,
"ERC721ABurnable: max batch size must be nonzero"
);
_name = name_;
_symbol = symbol_;
maxBatchSize = maxBatchSize_;
}
/**
* @dev See {IERC721Enumerable-totalSupply}.
*/functiontotalSupply() publicviewoverridereturns (uint256) {
return indexSupply.totalSupply;
}
/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/functiontokenByIndex(uint256 index)
publicviewoverridereturns (uint256)
{
require(
index < indexSupply.currentIndex,
"ERC721ABurnable: global index out of bounds"
);
return index;
}
/**
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
* This read function is O(totalSupply). If calling from a separate contract, be sure to test gas first.
* It may also degrade with extremely large collection sizes (e.g >> 10000), test for your use case.
*/functiontokenOfOwnerByIndex(address owner, uint256 index)
publicviewoverridereturns (uint256)
{
require(
index < balanceOf(owner),
"ERC721ABurnable: owner index out of bounds"
);
uint256 numMintedSoFar = totalSupply();
uint256 tokenIdsIdx =0;
address currOwnershipAddr =address(0);
for (uint256 i =0; i < numMintedSoFar; i++) {
TokenOwnership memory ownership = _ownerships[i];
if (ownership.addr !=address(0)) {
currOwnershipAddr = ownership.addr;
}
if (currOwnershipAddr == owner) {
if (tokenIdsIdx == index) {
return i;
}
tokenIdsIdx++;
}
}
revert("ERC721ABurnable: unable to get token of owner by index");
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId)
publicviewvirtualoverride(ERC165, IERC165)
returns (bool)
{
return
interfaceId ==type(IERC721).interfaceId||
interfaceId ==type(IERC721Metadata).interfaceId||
interfaceId ==type(IERC721Enumerable).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/functionbalanceOf(address owner) publicviewoverridereturns (uint256) {
require(
owner !=address(0),
"ERC721ABurnable: balance query for the zero address"
);
returnuint256(_addressData[owner].balance);
}
function_numberMinted(address owner) internalviewreturns (uint256) {
require(
owner !=address(0),
"ERC721ABurnable: number minted query for the zero address"
);
returnuint256(_addressData[owner].numberMinted);
}
functionownershipOf(uint256 tokenId)
internalviewreturns (TokenOwnership memory)
{
require(
_exists(tokenId),
"ERC721ABurnable: owner query for nonexistent token"
);
uint256 lowestTokenToCheck;
if (tokenId >= maxBatchSize) {
lowestTokenToCheck = tokenId - maxBatchSize +1;
}
for (uint256 curr = tokenId; curr >= lowestTokenToCheck; curr--) {
TokenOwnership memory ownership = _ownerships[curr];
if (ownership.addr !=address(0)) {
require(
ownership.addr != BURN_ADDRESS,
"ERC721ABurnable: owner query for nonexistent token"
);
return ownership;
}
}
revert("ERC721ABurnable: unable to determine the owner of token");
}
/**
* @dev See {IERC721-ownerOf}.
*/functionownerOf(uint256 tokenId)
publicviewvirtualoverridereturns (address)
{
return ownershipOf(tokenId).addr;
}
/**
* @dev See {IERC721Metadata-name}.
*/functionname() publicviewvirtualoverridereturns (stringmemory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/functionsymbol() publicviewvirtualoverridereturns (stringmemory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/functiontokenURI(uint256 tokenId)
publicviewvirtualoverridereturns (stringmemory)
{
require(
_exists(tokenId),
"ERC721Metadata: URI query for nonexistent token"
);
stringmemory baseURI = _baseURI();
returnbytes(baseURI).length>0
? string(abi.encodePacked(baseURI, tokenId.toString()))
: "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overriden in child contracts.
*/function_baseURI() internalviewvirtualreturns (stringmemory) {
return"";
}
/**
* @dev See {IERC721-approve}.
*/functionapprove(address to, uint256 tokenId) publicoverride{
address owner = ERC721ABurnable.ownerOf(tokenId);
require(to != owner, "ERC721ABurnable: approval to current owner");
require(
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721ABurnable: approve caller is not owner nor approved for all"
);
_approve(to, tokenId, owner);
}
/**
* @dev See {IERC721-getApproved}.
*/functiongetApproved(uint256 tokenId)
publicviewoverridereturns (address)
{
require(
_exists(tokenId),
"ERC721ABurnable: approved query for nonexistent token"
);
return _tokenApprovals[tokenId];
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/functionsetApprovalForAll(address operator, bool approved)
publicoverride{
require(operator != _msgSender(), "ERC721ABurnable: approve to caller");
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/functionisApprovedForAll(address owner, address operator)
publicviewvirtualoverridereturns (bool)
{
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) publicoverride{
_transfer(from, to, tokenId);
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) publicoverride{
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytesmemory _data
) publicoverride{
_transfer(from, to, tokenId);
require(
_checkOnERC721Received(from, to, tokenId, _data),
"ERC721ABurnable: transfer to non ERC721Receiver implementer"
);
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted (`_mint`),
*/function_exists(uint256 tokenId) internalviewreturns (bool) {
return tokenId < indexSupply.currentIndex;
}
function_safeMint(address to, uint256 quantity) internal{
_safeMint(to, quantity, "");
}
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` cannot be larger than the max batch size.
*
* Emits a {Transfer} event.
*/function_safeMint(address to,
uint256 quantity,
bytesmemory _data
) internal{
uint128 startTokenId = indexSupply.currentIndex;
require(to !=address(0), "ERC721ABurnable: mint to the zero address");
// We know if the first token in the batch doesn't exist, the other ones don't as well, because of serial ordering.require(
!_exists(startTokenId),
"ERC721ABurnable: token already minted"
);
require(
quantity <= maxBatchSize,
"ERC721ABurnable: quantity to mint too high"
);
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
AddressData memory addressData = _addressData[to];
_addressData[to] = AddressData(
addressData.balance+uint128(quantity),
addressData.numberMinted +uint128(quantity)
);
_ownerships[startTokenId] = TokenOwnership(to, uint64(block.timestamp));
uint128 updatedIndex = startTokenId;
for (uint256 i =0; i < quantity; i++) {
emit Transfer(address(0), to, updatedIndex);
require(
_checkOnERC721Received(address(0), to, updatedIndex, _data),
"ERC721ABurnable: transfer to non ERC721Receiver implementer"
);
updatedIndex++;
}
indexSupply.currentIndex +=uint128(quantity);
indexSupply.totalSupply +=uint128(quantity);
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/function_burn(uint256 tokenId) internalvirtual{
TokenOwnership memory owner = ERC721ABurnable.ownershipOf(tokenId);
bool isApprovedOrOwner = (_msgSender() == owner.addr ||
getApproved(tokenId) == _msgSender() ||
isApprovedForAll(owner.addr, _msgSender()));
require(
isApprovedOrOwner,
"ERC721ABurnable: transfer caller is not owner nor approved"
);
_beforeTokenTransfers(owner.addr, address(BURN_ADDRESS), tokenId, 1);
// Clear approvals
_approve(address(0), tokenId, owner.addr);
_addressData[owner.addr].balance-=1;
_ownerships[tokenId] = TokenOwnership(
BURN_ADDRESS,
uint64(block.timestamp)
);
// If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it.// Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.uint256 nextTokenId = tokenId +1;
if (_ownerships[nextTokenId].addr ==address(0)) {
if (_exists(nextTokenId)) {
_ownerships[nextTokenId] = TokenOwnership(
owner.addr,
owner.startTimestamp
);
}
}
// Decrement from total supply
indexSupply.totalSupply--;
emit Transfer(owner.addr, BURN_ADDRESS, tokenId);
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/function_transfer(addressfrom,
address to,
uint256 tokenId
) private{
TokenOwnership memory prevOwnership = ownershipOf(tokenId);
bool isApprovedOrOwner = (_msgSender() == prevOwnership.addr ||
getApproved(tokenId) == _msgSender() ||
isApprovedForAll(prevOwnership.addr, _msgSender()));
require(
isApprovedOrOwner,
"ERC721ABurnable: transfer caller is not owner nor approved"
);
require(
prevOwnership.addr ==from,
"ERC721ABurnable: transfer from incorrect owner"
);
require(
to !=address(0),
"ERC721ABurnable: transfer to the zero address"
);
_beforeTokenTransfers(from, to, tokenId, 1);
// Clear approvals from the previous owner
_approve(address(0), tokenId, prevOwnership.addr);
_addressData[from].balance-=1;
_addressData[to].balance+=1;
_ownerships[tokenId] = TokenOwnership(to, uint64(block.timestamp));
// If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it.// Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.uint256 nextTokenId = tokenId +1;
if (_ownerships[nextTokenId].addr ==address(0)) {
if (_exists(nextTokenId)) {
_ownerships[nextTokenId] = TokenOwnership(
prevOwnership.addr,
prevOwnership.startTimestamp
);
}
}
emit Transfer(from, to, tokenId);
_afterTokenTransfers(from, to, tokenId, 1);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* Emits a {Approval} event.
*/function_approve(address to,
uint256 tokenId,
address owner
) private{
_tokenApprovals[tokenId] = to;
emit Approval(owner, to, tokenId);
}
uint256public nextOwnerToExplicitlySet =0;
/**
* @dev Explicitly set `owners` to eliminate loops in future calls of ownerOf().
*/function_setOwnersExplicit(uint256 quantity) internal{
uint256 oldNextOwnerToSet = nextOwnerToExplicitlySet;
require(quantity >0, "quantity must be nonzero");
uint256 endIndex = oldNextOwnerToSet + quantity -1;
if (endIndex > indexSupply.currentIndex -1) {
endIndex = indexSupply.currentIndex -1;
}
// We know if the last one in the group exists, all in the group exist, due to serial ordering.require(_exists(endIndex), "not enough minted yet for this cleanup");
for (uint256 i = oldNextOwnerToSet; i <= endIndex; i++) {
if (_ownerships[i].addr ==address(0)) {
TokenOwnership memory ownership = ownershipOf(i);
_ownerships[i] = TokenOwnership(
ownership.addr,
ownership.startTimestamp
);
}
}
nextOwnerToExplicitlySet = endIndex +1;
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
* The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return bool whether the call correctly returned the expected magic value
*/function_checkOnERC721Received(addressfrom,
address to,
uint256 tokenId,
bytesmemory _data
) privatereturns (bool) {
if (to.isContract()) {
try
IERC721Receiver(to).onERC721Received(
_msgSender(),
from,
tokenId,
_data
)
returns (bytes4 retval) {
return retval == IERC721Receiver(to).onERC721Received.selector;
} catch (bytesmemory reason) {
if (reason.length==0) {
revert(
"ERC721ABurnable: transfer to non ERC721Receiver implementer"
);
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
returntrue;
}
}
/**
* @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting.
*
* startTokenId - the first token id to be transferred
* quantity - the amount to be transferred
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
*/function_beforeTokenTransfers(addressfrom,
address to,
uint256 startTokenId,
uint256 quantity
) internalvirtual{}
/**
* @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes
* minting.
*
* startTokenId - the first token id to be transferred
* quantity - the amount to be transferred
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero.
* - `from` and `to` are never both zero.
*/function_afterTokenTransfers(addressfrom,
address to,
uint256 startTokenId,
uint256 quantity
) internalvirtual{}
}
Contract Source Code
File 7 of 17: IContractURI.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.4;import"@openzeppelin/contracts/utils/introspection/IERC165.sol";
////// @dev Interface for the proposed contractURI standard///interfaceIContractURIisIERC165{
/// ERC165 bytes to add to interface array - set in parent contract/// implementing this standard////// bytes4(keccak256("contractURI()")) == 0xe8a3d485/// @notice Called to return the URI pertaining to the contract metadata/// @return contractURI - the URI that pertaining to the contract metadatafunctioncontractURI() externalviewreturns (stringmemory);
}
Contract Source Code
File 8 of 17: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 9 of 17: IERC2981.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.4;import"@openzeppelin/contracts/utils/introspection/IERC165.sol";
////// @dev Interface for the NFT Royalty Standard///interfaceIERC2981isIERC165{
/// ERC165 bytes to add to interface array - set in parent contract/// implementing this standard////// bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a/// bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;/// _registerInterface(_INTERFACE_ID_ERC2981);/// @notice Called with the sale price to determine how much royalty// is owed and to whom./// @param _tokenId - the NFT asset queried for royalty information/// @param _salePrice - the sale price of the NFT asset specified by _tokenId/// @return receiver - address of who should be sent the royalty payment/// @return royaltyAmount - the royalty payment amount for _salePricefunctionroyaltyInfo(uint256 _tokenId, uint256 _salePrice)
externalviewreturns (address receiver, uint256 royaltyAmount);
}
Contract Source Code
File 10 of 17: IERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721isIERC165{
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/functionapprove(address to, uint256 tokenId) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata data
) external;
}
Contract Source Code
File 11 of 17: IERC721Enumerable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Enumerable.sol)pragmasolidity ^0.8.0;import"../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/interfaceIERC721EnumerableisIERC721{
/**
* @dev Returns the total amount of tokens stored by the contract.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/functiontokenOfOwnerByIndex(address owner, uint256 index) externalviewreturns (uint256 tokenId);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/functiontokenByIndex(uint256 index) externalviewreturns (uint256);
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)pragmasolidity ^0.8.0;/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/interfaceIERC721Receiver{
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
*/functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 14 of 17: MerkleProof.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/cryptography/MerkleProof.sol)pragmasolidity ^0.8.0;/**
* @dev These functions deal with verification of Merkle Trees proofs.
*
* The proofs can be generated using the JavaScript library
* https://github.com/miguelmota/merkletreejs[merkletreejs].
* Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
*
* See `test/utils/cryptography/MerkleProof.test.js` for some examples.
*/libraryMerkleProof{
/**
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
* defined by `root`. For this, a `proof` must be provided, containing
* sibling hashes on the branch from the leaf to the root of the tree. Each
* pair of leaves and each pair of pre-images are assumed to be sorted.
*/functionverify(bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internalpurereturns (bool) {
return processProof(proof, leaf) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merklee tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. When processing the proof, the pairs
* of leafs & pre-images are assumed to be sorted.
*
* _Available since v4.4._
*/functionprocessProof(bytes32[] memory proof, bytes32 leaf) internalpurereturns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i =0; i < proof.length; i++) {
bytes32 proofElement = proof[i];
if (computedHash <= proofElement) {
// Hash(current computed hash + current element of the proof)
computedHash =keccak256(abi.encodePacked(computedHash, proofElement));
} else {
// Hash(current element of the proof + current computed hash)
computedHash =keccak256(abi.encodePacked(proofElement, computedHash));
}
}
return computedHash;
}
}
Contract Source Code
File 15 of 17: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)pragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 16 of 17: Royalty.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.4;import"@openzeppelin/contracts/access/Ownable.sol";
import"@openzeppelin/contracts/utils/introspection/ERC165.sol";
import"./IERC2981.sol";
abstractcontractRoyaltyisOwnable, ERC165, IERC2981{
addresspublic royaltyReceiver;
uint32public royaltyBasisPoints; // A integer representing 1/100th of 1% (fixed point with 100 = 1.00%)constructor(address _receiver, uint32 _basisPoints) {
royaltyReceiver = _receiver;
royaltyBasisPoints = _basisPoints;
}
functionsetRoyaltyReceiver(address _receiver) externalvirtualonlyOwner{
royaltyReceiver = _receiver;
}
functionsetRoyaltyBasisPoints(uint32 _basisPoints)
externalvirtualonlyOwner{
royaltyBasisPoints = _basisPoints;
}
functionroyaltyInfo(uint256, uint256 _salePrice)
publicviewvirtualoverridereturns (address receiver, uint256 amount)
{
// All tokens return the same royalty amount to the receiveruint256 _royaltyAmount = (_salePrice * royaltyBasisPoints) /10000; // Normalises in basis points reference. (10000 = 100.00%)return (royaltyReceiver, _royaltyAmount);
}
// Compulsory overridesfunctionsupportsInterface(bytes4 interfaceId)
publicviewvirtualoverride(ERC165, IERC165)
returns (bool)
{
return
interfaceId ==type(IERC2981).interfaceId||super.supportsInterface(interfaceId);
}
}
Contract Source Code
File 17 of 17: Strings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)pragmasolidity ^0.8.0;/**
* @dev String operations.
*/libraryStrings{
bytes16privateconstant _HEX_SYMBOLS ="0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
// Inspired by OraclizeAPI's implementation - MIT licence// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.solif (value ==0) {
return"0";
}
uint256 temp = value;
uint256 digits;
while (temp !=0) {
digits++;
temp /=10;
}
bytesmemory buffer =newbytes(digits);
while (value !=0) {
digits -=1;
buffer[digits] =bytes1(uint8(48+uint256(value %10)));
value /=10;
}
returnstring(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
if (value ==0) {
return"0x00";
}
uint256 temp = value;
uint256 length =0;
while (temp !=0) {
length++;
temp >>=8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/functiontoHexString(uint256 value, uint256 length) internalpurereturns (stringmemory) {
bytesmemory buffer =newbytes(2* length +2);
buffer[0] ="0";
buffer[1] ="x";
for (uint256 i =2* length +1; i >1; --i) {
buffer[i] = _HEX_SYMBOLS[value &0xf];
value >>=4;
}
require(value ==0, "Strings: hex length insufficient");
returnstring(buffer);
}
}