Skip to content

Commit 85d1be5

Browse files
nkrishangkumaryash90Krishang Nadgaudajoaquim-verges
authored
Contracts SDK: base/ERC721 contracts (#191)
* initial changes for base contracts * update feature/Drop * Add base/NFTDrop * silence test error * run prettier * wip: base + drop * wip: added customizable uri, tokenID, royalty variations * lazymint import * forge update * add ERC721, Base and Drop * Add public var nextTokenIdToMint * isAuthorizedSigner -> canSignMintRequest * update ERC721SignatureMint * add ERC721LazyMint * add ERC721DelayedRevea * remove deprecated extensions * add ERC20 and ERC20Base * add ERC1155 and ERC1155Base * add ERC20SignatureMint * forge updates * docs update * Add ERC721A base * Extract BatchMintMetadata from LazyMint * use BatchMintMetadata in ERC721ABase and derived contracts * _batchMint -> _batchMintMetadata * use ERC721A base in ERC721SignatureMint * ERC1155SignatureMint * incomplete ERC721Drop * wip ERC20 contracts * wip ERC1155 drop * add batchMint function to ERC1155Base * add ERC1155LazyMint * add ERC1155DelayedReveal * Add natspec comments for ERC721 * Cleanup ERC721Base with natspec comments * Cleanup ERC721ABase with natspec comments * add burn functionality to ERC721Base and ERC721ABase * add DropUpdated and DropSinglePhaseUpdated * Cleanup ERC721LazyMint and its deps with natspec comments * add ERC1155Drop * cleanup ERC721DR and deps with natspec comments * cleanup ERC721SignatureMint with natspec comments * init primarySale recipient in constructor * cleanup ERC721Drop with natspec comments * revert changes to prod feature/Royalty * forge updates * Delete non ERC721 base offerings * Use separate Royalty contrac * docs update * remove erc721a external dependency from /base * remove external deps from ERC721SignatureMint * rename feature -> extension * run prettier * docs update * fix forge build errors * rename ERC721ABase -> ERC721Base * move ERC721 base contracts out of /ERC721 directory * pkg release * DS_Store * Update Royalty extension; now inherits IERC2981 * Update /base contract imports for Royalty * Update supportsInterface for prebuilt contracts post Royalty update * update LazyMint; use extracted out BatchMintMetadata * delete unused extension updates * run prettier * remove custom errors from /base and new /extensions * yarn run prettier * fix test errors * update description for ERC721Base * Update require string for unimplemented mint fn * mention EIP712 in ERC721SigMint description * delete duplicated Strings and Address library * Add batchMint for multiple and mint for single * run prettier * remove contractURI arg from constructor * pkg release * remove unused and external imports * pkg release * rename mint to mintTo * use fullURI for mintTo * override functions declared in interfaces * remove unused constructor arg * run prettier * pkg release * use 0.8.0 * pkg release * revert back to 0.8.4 for ERC721A deps * pkg release * add missing override in reveal * use 0.8.0 in IWETH * use 0.8.0 in MerkleProof * pkg release * add missing override to reveal in ERC721Drop * pkg release * correct nextTokenIdToMint behaviour * pkg release * fix IERC721 incompatibility with other contracts * rename batchMint to batchMintTo * rename batchMintTo in other bases * update docs * override nextTokenIdToMint in Drop as well * docs * 3.0.0-103.0.0-103.0.0-10 * change public -> internal nextTokenIdToLazyMint * Fix getters in PermissionsEnumerable * Optimizer 800 -> 600 * docs update * tests for TransferRole behaviour in SigDrop * run prettier * update optimizer 800 -> 600 for forge * Fix revert strings in test file Co-authored-by: Yash <[email protected]> Co-authored-by: Krishang Nadgauda <[email protected]> Co-authored-by: Joaquim Verges <[email protected]>
1 parent 956b3d8 commit 85d1be5

File tree

125 files changed

+9287
-756
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+9287
-756
lines changed

.DS_Store

0 Bytes
Binary file not shown.

contracts/base/ERC721Base.sol

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import { ERC721A } from "../eip/ERC721A.sol";
5+
6+
import "../extension/ContractMetadata.sol";
7+
import "../extension/Multicall.sol";
8+
import "../extension/Ownable.sol";
9+
import "../extension/Royalty.sol";
10+
import "../extension/BatchMintMetadata.sol";
11+
12+
import "../lib/TWStrings.sol";
13+
14+
/**
15+
* The `ERC721Base` smart contract implements the ERC721 NFT standard, along with the ERC721A optimization to the standard.
16+
* It includes the following additions to standard ERC721 logic:
17+
*
18+
* - Ability to mint NFTs via the provided `mint` function.
19+
*
20+
* - Contract metadata for royalty support on platforms such as OpenSea that use
21+
* off-chain information to distribute roaylties.
22+
*
23+
* - Ownership of the contract, with the ability to restrict certain functions to
24+
* only be called by the contract's owner.
25+
*
26+
* - Multicall capability to perform multiple actions atomically
27+
*
28+
* - EIP 2981 compliance for royalty support on NFT marketplaces.
29+
*/
30+
31+
contract ERC721Base is ERC721A, ContractMetadata, Multicall, Ownable, Royalty, BatchMintMetadata {
32+
using TWStrings for uint256;
33+
34+
/*//////////////////////////////////////////////////////////////
35+
Mappings
36+
//////////////////////////////////////////////////////////////*/
37+
38+
mapping(uint256 => string) private fullURI;
39+
40+
/*//////////////////////////////////////////////////////////////
41+
Constructor
42+
//////////////////////////////////////////////////////////////*/
43+
44+
constructor(
45+
string memory _name,
46+
string memory _symbol,
47+
address _royaltyRecipient,
48+
uint128 _royaltyBps
49+
) ERC721A(_name, _symbol) {
50+
_setupOwner(msg.sender);
51+
_setupDefaultRoyaltyInfo(_royaltyRecipient, _royaltyBps);
52+
}
53+
54+
/*//////////////////////////////////////////////////////////////
55+
ERC165 Logic
56+
//////////////////////////////////////////////////////////////*/
57+
58+
/// @dev See ERC165: https://eips.ethereum.org/EIPS/eip-165
59+
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, IERC165) returns (bool) {
60+
return
61+
interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
62+
interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
63+
interfaceId == 0x5b5e139f || // ERC165 Interface ID for ERC721Metadata
64+
interfaceId == type(IERC2981).interfaceId; // ERC165 ID for ERC2981
65+
}
66+
67+
/*//////////////////////////////////////////////////////////////
68+
Overriden ERC721 logic
69+
//////////////////////////////////////////////////////////////*/
70+
71+
/**
72+
* @notice Returns the metadata URI for an NFT.
73+
* @dev See `BatchMintMetadata` for handling of metadata in this contract.
74+
*
75+
* @param _tokenId The tokenId of an NFT.
76+
*/
77+
function tokenURI(uint256 _tokenId) public view virtual override returns (string memory) {
78+
string memory fullUriForToken = fullURI[_tokenId];
79+
if (bytes(fullUriForToken).length > 0) {
80+
return fullUriForToken;
81+
}
82+
83+
string memory batchUri = getBaseURI(_tokenId);
84+
return string(abi.encodePacked(batchUri, _tokenId.toString()));
85+
}
86+
87+
/*//////////////////////////////////////////////////////////////
88+
Minting logic
89+
//////////////////////////////////////////////////////////////*/
90+
91+
/**
92+
* @notice Lets an authorized address mint an NFT to a recipient.
93+
* @dev The logic in the `_canMint` function determines whether the caller is authorized to mint NFTs.
94+
*
95+
* @param _to The recipient of the NFT to mint.
96+
* @param _tokenURI The full metadata URI for the NFT minted.
97+
*/
98+
function mintTo(address _to, string memory _tokenURI) public virtual {
99+
require(_canMint(), "Not authorized to mint.");
100+
fullURI[nextTokenIdToMint()] = _tokenURI;
101+
_safeMint(_to, 1, "");
102+
}
103+
104+
/**
105+
* @notice Lets an authorized address mint multiple NFTs at once to a recipient.
106+
* @dev The logic in the `_canMint` function determines whether the caller is authorized to mint NFTs.
107+
*
108+
* @param _to The recipient of the NFT to mint.
109+
* @param _quantity The number of NFTs to mint.
110+
* @param _baseURI The baseURI for the `n` number of NFTs minted. The metadata for each NFT is `baseURI/tokenId`
111+
* @param _data Additional data to pass along during the minting of the NFT.
112+
*/
113+
function batchMintTo(
114+
address _to,
115+
uint256 _quantity,
116+
string memory _baseURI,
117+
bytes memory _data
118+
) public virtual {
119+
require(_canMint(), "Not authorized to mint.");
120+
_batchMintMetadata(nextTokenIdToMint(), _quantity, _baseURI);
121+
_safeMint(_to, _quantity, _data);
122+
}
123+
124+
/**
125+
* @notice Lets an owner or approved operator burn the NFT of the given tokenId.
126+
* @dev ERC721A's `_burn(uint256,bool)` internally checks for token approvals.
127+
*
128+
* @param _tokenId The tokenId of the NFT to burn.
129+
*/
130+
function burn(uint256 _tokenId) external virtual {
131+
_burn(_tokenId, true);
132+
}
133+
134+
/*//////////////////////////////////////////////////////////////
135+
Public getters
136+
//////////////////////////////////////////////////////////////*/
137+
138+
/// @notice The tokenId assigned to the next new NFT to be minted.
139+
function nextTokenIdToMint() public view virtual returns (uint256) {
140+
return _currentIndex;
141+
}
142+
143+
/*//////////////////////////////////////////////////////////////
144+
Internal (overrideable) functions
145+
//////////////////////////////////////////////////////////////*/
146+
147+
/// @dev Returns whether contract metadata can be set in the given execution context.
148+
function _canSetContractURI() internal view virtual override returns (bool) {
149+
return msg.sender == owner();
150+
}
151+
152+
/// @dev Returns whether a token can be minted in the given execution context.
153+
function _canMint() internal view virtual returns (bool) {
154+
return msg.sender == owner();
155+
}
156+
157+
/// @dev Returns whether owner can be set in the given execution context.
158+
function _canSetOwner() internal view virtual override returns (bool) {
159+
return msg.sender == owner();
160+
}
161+
162+
/// @dev Returns whether royalty info can be set in the given execution context.
163+
function _canSetRoyaltyInfo() internal view virtual override returns (bool) {
164+
return msg.sender == owner();
165+
}
166+
}
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import "./ERC721LazyMint.sol";
5+
6+
import "../extension/DelayedReveal.sol";
7+
8+
/**
9+
* BASE: ERC721A
10+
* EXTENSION: LazyMint, DelayedReveal
11+
*
12+
* The `ERC721DelayedReveal` contract uses the `ERC721Base` contract, along with the `LazyMint` and `DelayedReveal` extension.
13+
*
14+
* 'Lazy minting' means defining the metadata of NFTs without minting it to an address. Regular 'minting'
15+
* of NFTs means actually assigning an owner to an NFT.
16+
*
17+
* As a contract admin, this lets you prepare the metadata for NFTs that will be minted by an external party,
18+
* without paying the gas cost for actually minting the NFTs.
19+
*
20+
* 'Delayed reveal' is a mechanism by which you can distribute NFTs to your audience and reveal the metadata of the distributed
21+
* NFTs, after the fact.
22+
*
23+
* You can read more about how the `DelayedReveal` extension works, here: https://blog.thirdweb.com/delayed-reveal-nfts
24+
*/
25+
26+
contract ERC721DelayedReveal is ERC721LazyMint, DelayedReveal {
27+
using TWStrings for uint256;
28+
29+
/*//////////////////////////////////////////////////////////////
30+
Constructor
31+
//////////////////////////////////////////////////////////////*/
32+
33+
constructor(
34+
string memory _name,
35+
string memory _symbol,
36+
address _royaltyRecipient,
37+
uint128 _royaltyBps
38+
) ERC721LazyMint(_name, _symbol, _royaltyRecipient, _royaltyBps) {}
39+
40+
/*//////////////////////////////////////////////////////////////
41+
Overriden ERC721 logic
42+
//////////////////////////////////////////////////////////////*/
43+
44+
/**
45+
* @notice Returns the metadata URI for an NFT.
46+
* @dev See `BatchMintMetadata` for handling of metadata in this contract.
47+
*
48+
* @param _tokenId The tokenId of an NFT.
49+
*/
50+
function tokenURI(uint256 _tokenId) public view override returns (string memory) {
51+
uint256 batchId = getBatchId(_tokenId);
52+
string memory batchUri = getBaseURI(_tokenId);
53+
54+
if (isEncryptedBatch(batchId)) {
55+
return string(abi.encodePacked(batchUri, "0"));
56+
} else {
57+
return string(abi.encodePacked(batchUri, _tokenId.toString()));
58+
}
59+
}
60+
61+
/*//////////////////////////////////////////////////////////////
62+
Lazy minting logic
63+
//////////////////////////////////////////////////////////////*/
64+
65+
/**
66+
* @notice Lets an authorized address lazy mint a given amount of NFTs.
67+
*
68+
* @param _amount The number of NFTs to lazy mint.
69+
* @param _baseURIForTokens The placeholder base URI for the 'n' number of NFTs being lazy minted, where the
70+
* metadata for each of those NFTs is `${baseURIForTokens}/${tokenId}`.
71+
* @param _encryptedBaseURI The encrypted base URI for the batch of NFTs being lazy minted.
72+
* @return batchId A unique integer identifier for the batch of NFTs lazy minted together.
73+
*/
74+
function lazyMint(
75+
uint256 _amount,
76+
string calldata _baseURIForTokens,
77+
bytes calldata _encryptedBaseURI
78+
) public virtual override returns (uint256 batchId) {
79+
if (_encryptedBaseURI.length != 0) {
80+
_setEncryptedBaseURI(nextTokenIdToLazyMint + _amount, _encryptedBaseURI);
81+
}
82+
83+
return super.lazyMint(_amount, _baseURIForTokens, _encryptedBaseURI);
84+
}
85+
86+
/*//////////////////////////////////////////////////////////////
87+
Delayed reveal logic
88+
//////////////////////////////////////////////////////////////*/
89+
90+
/**
91+
* @notice Lets an authorized address reveal a batch of delayed reveal NFTs.
92+
*
93+
* @param _index The ID for the batch of delayed-reveal NFTs to reveal.
94+
* @param _key The key with which the base URI for the relevant batch of NFTs was encrypted.
95+
*/
96+
function reveal(uint256 _index, bytes calldata _key) external virtual override returns (string memory revealedURI) {
97+
require(_canReveal(), "Not authorized");
98+
99+
uint256 batchId = getBatchIdAtIndex(_index);
100+
revealedURI = getRevealURI(batchId, _key);
101+
102+
_setEncryptedBaseURI(batchId, "");
103+
_setBaseURI(batchId, revealedURI);
104+
105+
emit TokenURIRevealed(_index, revealedURI);
106+
}
107+
108+
/// @dev Checks whether NFTs can be revealed in the given execution context.
109+
function _canReveal() internal view virtual returns (bool) {
110+
return msg.sender == owner();
111+
}
112+
}

0 commit comments

Comments
 (0)