Skip to content

Commit 0532c04

Browse files
nkrishangKrishang Nadgaudajoaquim-verges
authored
Con215 - Update to Delayed Reveal functionality (#204)
* Update DelayedReveal extension * reduce optimizer runs by 10 * bump Sigdrop version 2 -> 3 * updated delayed reveal for DropERC721 * Bump DropERC721 version 2 -> 3 * fix lazy mint logic * fix encryptedBaseURI -> data * docs update * correct comments * run prettier * fix tests * fix pkg version * docs update * pkg release * update encryptedData check in lazy mint * do not check for data length * check if is empty in lazyMint() * fix tests for regular lazy mint * generated docs update * pkg release * Add IDelayedRevealDeprecated * pkg release * move MockContractPublisher to expose it to the SDK * fix test * fix lint Co-authored-by: Krishang Nadgauda <[email protected]> Co-authored-by: Joaquim Verges <[email protected]>
1 parent 97d7628 commit 0532c04

28 files changed

+644
-243
lines changed

contracts/base/ERC721DelayedReveal.sol

+10-7
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,22 @@ contract ERC721DelayedReveal is ERC721LazyMint, DelayedReveal {
6868
* @param _amount The number of NFTs to lazy mint.
6969
* @param _baseURIForTokens The placeholder base URI for the 'n' number of NFTs being lazy minted, where the
7070
* metadata for each of those NFTs is `${baseURIForTokens}/${tokenId}`.
71-
* @param _encryptedBaseURI The encrypted base URI for the batch of NFTs being lazy minted.
71+
* @param _data The encrypted base URI + provenance hash for the batch of NFTs being lazy minted.
7272
* @return batchId A unique integer identifier for the batch of NFTs lazy minted together.
7373
*/
7474
function lazyMint(
7575
uint256 _amount,
7676
string calldata _baseURIForTokens,
77-
bytes calldata _encryptedBaseURI
78-
) public virtual override returns (uint256 batchId) {
79-
if (_encryptedBaseURI.length != 0) {
80-
_setEncryptedBaseURI(nextTokenIdToLazyMint + _amount, _encryptedBaseURI);
77+
bytes calldata _data
78+
) public override returns (uint256 batchId) {
79+
if (_data.length > 0) {
80+
(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(_data, (bytes, bytes32));
81+
if (encryptedURI.length != 0 && provenanceHash != "") {
82+
_setEncryptedData(nextTokenIdToLazyMint + _amount, _data);
83+
}
8184
}
8285

83-
return super.lazyMint(_amount, _baseURIForTokens, _encryptedBaseURI);
86+
return super.lazyMint(_amount, _baseURIForTokens, _data);
8487
}
8588

8689
/*//////////////////////////////////////////////////////////////
@@ -99,7 +102,7 @@ contract ERC721DelayedReveal is ERC721LazyMint, DelayedReveal {
99102
uint256 batchId = getBatchIdAtIndex(_index);
100103
revealedURI = getRevealURI(batchId, _key);
101104

102-
_setEncryptedBaseURI(batchId, "");
105+
_setEncryptedData(batchId, "");
103106
_setBaseURI(batchId, revealedURI);
104107

105108
emit TokenURIRevealed(_index, revealedURI);

contracts/base/ERC721Drop.sol

+10-7
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,22 @@ contract ERC721Drop is ERC721SignatureMint, LazyMint, DelayedReveal, DropSingleP
115115
* @param _amount The number of NFTs to lazy mint.
116116
* @param _baseURIForTokens The placeholder base URI for the 'n' number of NFTs being lazy minted, where the
117117
* metadata for each of those NFTs is `${baseURIForTokens}/${tokenId}`.
118-
* @param _encryptedBaseURI The encrypted base URI for the batch of NFTs being lazy minted.
118+
* @param _data The encrypted base URI + provenance hash for the batch of NFTs being lazy minted.
119119
* @return batchId A unique integer identifier for the batch of NFTs lazy minted together.
120120
*/
121121
function lazyMint(
122122
uint256 _amount,
123123
string calldata _baseURIForTokens,
124-
bytes calldata _encryptedBaseURI
125-
) public virtual override returns (uint256 batchId) {
126-
if (_encryptedBaseURI.length != 0) {
127-
_setEncryptedBaseURI(nextTokenIdToLazyMint + _amount, _encryptedBaseURI);
124+
bytes calldata _data
125+
) public override returns (uint256 batchId) {
126+
if (_data.length > 0) {
127+
(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(_data, (bytes, bytes32));
128+
if (encryptedURI.length != 0 && provenanceHash != "") {
129+
_setEncryptedData(nextTokenIdToLazyMint + _amount, _data);
130+
}
128131
}
129132

130-
return LazyMint.lazyMint(_amount, _baseURIForTokens, _encryptedBaseURI);
133+
return LazyMint.lazyMint(_amount, _baseURIForTokens, _data);
131134
}
132135

133136
/// @notice The tokenId assigned to the next new NFT to be lazy minted.
@@ -151,7 +154,7 @@ contract ERC721Drop is ERC721SignatureMint, LazyMint, DelayedReveal, DropSingleP
151154
uint256 batchId = getBatchIdAtIndex(_index);
152155
revealedURI = getRevealURI(batchId, _key);
153156

154-
_setEncryptedBaseURI(batchId, "");
157+
_setEncryptedData(batchId, "");
155158
_setBaseURI(batchId, revealedURI);
156159

157160
emit TokenURIRevealed(_index, revealedURI);

contracts/drop/DropERC721.sol

+17-9
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ contract DropERC721 is
5454
//////////////////////////////////////////////////////////////*/
5555

5656
bytes32 private constant MODULE_TYPE = bytes32("DropERC721");
57-
uint256 private constant VERSION = 2;
57+
uint256 private constant VERSION = 3;
5858

5959
/// @dev Only transfers to or from TRANSFER_ROLE holders are valid, when transfers are restricted.
6060
bytes32 private constant TRANSFER_ROLE = keccak256("TRANSFER_ROLE");
@@ -117,7 +117,7 @@ contract DropERC721 is
117117
* @dev Mapping from 'Largest tokenId of a batch of 'delayed-reveal' tokens with
118118
* the same baseURI' to encrypted base URI for the respective batch of tokens.
119119
**/
120-
mapping(uint256 => bytes) public encryptedBaseURI;
120+
mapping(uint256 => bytes) public encryptedData;
121121

122122
/// @dev Mapping from address => total number of NFTs a wallet has claimed.
123123
mapping(address => uint256) public walletClaimCount;
@@ -193,7 +193,7 @@ contract DropERC721 is
193193
function tokenURI(uint256 _tokenId) public view override returns (string memory) {
194194
for (uint256 i = 0; i < baseURIIndices.length; i += 1) {
195195
if (_tokenId < baseURIIndices[i]) {
196-
if (encryptedBaseURI[baseURIIndices[i]].length != 0) {
196+
if (encryptedData[baseURIIndices[i]].length != 0) {
197197
return string(abi.encodePacked(baseURI[baseURIIndices[i]], "0"));
198198
} else {
199199
return string(abi.encodePacked(baseURI[baseURIIndices[i]], _tokenId.toString()));
@@ -238,7 +238,7 @@ contract DropERC721 is
238238
function lazyMint(
239239
uint256 _amount,
240240
string calldata _baseURIForTokens,
241-
bytes calldata _encryptedBaseURI
241+
bytes calldata _data
242242
) external onlyRole(MINTER_ROLE) {
243243
uint256 startId = nextTokenIdToMint;
244244
uint256 baseURIIndex = startId + _amount;
@@ -247,11 +247,15 @@ contract DropERC721 is
247247
baseURI[baseURIIndex] = _baseURIForTokens;
248248
baseURIIndices.push(baseURIIndex);
249249

250-
if (_encryptedBaseURI.length != 0) {
251-
encryptedBaseURI[baseURIIndex] = _encryptedBaseURI;
250+
if (_data.length > 0) {
251+
(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(_data, (bytes, bytes32));
252+
253+
if (encryptedURI.length != 0 && provenanceHash != "") {
254+
encryptedData[baseURIIndex] = _data;
255+
}
252256
}
253257

254-
emit TokensLazyMinted(startId, startId + _amount - 1, _baseURIForTokens, _encryptedBaseURI);
258+
emit TokensLazyMinted(startId, startId + _amount - 1, _baseURIForTokens, _data);
255259
}
256260

257261
/// @dev Lets an account with `MINTER_ROLE` reveal the URI for a batch of 'delayed-reveal' NFTs.
@@ -263,13 +267,17 @@ contract DropERC721 is
263267
require(index < baseURIIndices.length, "invalid index.");
264268

265269
uint256 _index = baseURIIndices[index];
266-
bytes memory encryptedURI = encryptedBaseURI[_index];
270+
bytes memory data = encryptedData[_index];
271+
(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(data, (bytes, bytes32));
272+
267273
require(encryptedURI.length != 0, "nothing to reveal.");
268274

269275
revealedURI = string(encryptDecrypt(encryptedURI, _key));
270276

277+
require(keccak256(abi.encodePacked(revealedURI, _key, block.chainid)) == provenanceHash, "Incorrect key");
278+
271279
baseURI[_index] = revealedURI;
272-
delete encryptedBaseURI[_index];
280+
delete encryptedData[_index];
273281

274282
emit NFTRevealed(_index, revealedURI);
275283

contracts/extension/DelayedReveal.sol

+12-8
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import "./interface/IDelayedReveal.sol";
1010
*/
1111

1212
abstract contract DelayedReveal is IDelayedReveal {
13-
/// @dev Mapping from id of a batch of tokens => to encrypted base URI for the respective batch of tokens.
14-
mapping(uint256 => bytes) public encryptedBaseURI;
13+
/// @dev Mapping from tokenId of a batch of tokens => to delayed reveal data.
14+
mapping(uint256 => bytes) public encryptedData;
1515

16-
/// @dev Sets the encrypted baseURI for a batch of tokenIds.
17-
function _setEncryptedBaseURI(uint256 _batchId, bytes memory _encryptedBaseURI) internal {
18-
encryptedBaseURI[_batchId] = _encryptedBaseURI;
16+
/// @dev Sets the delayed reveal data for a batchId.
17+
function _setEncryptedData(uint256 _batchId, bytes memory _encryptedData) internal {
18+
encryptedData[_batchId] = _encryptedData;
1919
}
2020

2121
/**
@@ -30,12 +30,16 @@ abstract contract DelayedReveal is IDelayedReveal {
3030
* @return revealedURI Decrypted base URI.
3131
*/
3232
function getRevealURI(uint256 _batchId, bytes calldata _key) public view returns (string memory revealedURI) {
33-
bytes memory encryptedURI = encryptedBaseURI[_batchId];
34-
if (encryptedURI.length == 0) {
33+
bytes memory data = encryptedData[_batchId];
34+
if (data.length == 0) {
3535
revert("Nothing to reveal");
3636
}
3737

38+
(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(data, (bytes, bytes32));
39+
3840
revealedURI = string(encryptDecrypt(encryptedURI, _key));
41+
42+
require(keccak256(abi.encodePacked(revealedURI, _key, block.chainid)) == provenanceHash, "Incorrect key");
3943
}
4044

4145
/**
@@ -89,6 +93,6 @@ abstract contract DelayedReveal is IDelayedReveal {
8993
* @param _batchId ID of a batch of NFTs.
9094
*/
9195
function isEncryptedBatch(uint256 _batchId) public view returns (bool) {
92-
return encryptedBaseURI[_batchId].length > 0;
96+
return encryptedData[_batchId].length > 0;
9397
}
9498
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
// [ DEPRECATED CONTRACT: use `contracts/extension/interface/IDelayedReveal.sol` instead ]
5+
6+
/**
7+
* Thirdweb's `DelayedReveal` is a contract extension for base NFT contracts. It lets you create batches of
8+
* 'delayed-reveal' NFTs. You can learn more about the usage of delayed reveal NFTs here - https://blog.thirdweb.com/delayed-reveal-nfts
9+
*/
10+
11+
interface IDelayedRevealDeprecated {
12+
/// @dev Emitted when tokens are revealed.
13+
event TokenURIRevealed(uint256 indexed index, string revealedURI);
14+
15+
/// @dev Returns the encrypted base URI associated with the given identifier.
16+
function encryptedBaseURI(uint256 identifier) external view returns (bytes memory);
17+
18+
/**
19+
* @notice Reveals a batch of delayed reveal NFTs.
20+
*
21+
* @param identifier The ID for the batch of delayed-reveal NFTs to reveal.
22+
*
23+
* @param key The key with which the base URI for the relevant batch of NFTs was encrypted.
24+
*/
25+
function reveal(uint256 identifier, bytes calldata key) external returns (string memory revealedURI);
26+
27+
/**
28+
* @notice Performs XOR encryption/decryption.
29+
*
30+
* @param data The data to encrypt. In the case of delayed-reveal NFTs, this is the "revealed" state
31+
* base URI of the relevant batch of NFTs.
32+
*
33+
* @param key The key with which to encrypt data
34+
*/
35+
function encryptDecrypt(bytes memory data, bytes calldata key) external pure returns (bytes memory result);
36+
}
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.11;
3+
4+
import "../interfaces/IContractPublisher.sol";
5+
6+
// solhint-disable const-name-snakecase
7+
contract MockContractPublisher is IContractPublisher {
8+
function getAllPublishedContracts(address)
9+
external
10+
pure
11+
override
12+
returns (CustomContractInstance[] memory published)
13+
{
14+
CustomContractInstance[] memory mocks = new CustomContractInstance[](1);
15+
mocks[0] = CustomContractInstance(
16+
"MockContract",
17+
123,
18+
"ipfs://mock",
19+
0x0000000000000000000000000000000000000000000000000000000000000001,
20+
address(0x0000000000000000000000000000000000000000)
21+
);
22+
return mocks;
23+
}
24+
25+
function getPublishedContractVersions(address, string memory)
26+
external
27+
pure
28+
returns (CustomContractInstance[] memory published)
29+
{
30+
return new CustomContractInstance[](0);
31+
}
32+
33+
function getPublishedContract(address, string memory)
34+
external
35+
pure
36+
returns (CustomContractInstance memory published)
37+
{
38+
return CustomContractInstance("", 0, "", "", address(0));
39+
}
40+
41+
function publishContract(
42+
address publisher,
43+
string memory contractId,
44+
string memory publishMetadataUri,
45+
string memory compilerMetadataUri,
46+
bytes32 bytecodeHash,
47+
address implementation
48+
) external {}
49+
50+
function unpublishContract(address publisher, string memory contractId) external {}
51+
52+
function setPublisherProfileUri(address, string memory) external {}
53+
54+
function getPublisherProfileUri(address) external pure returns (string memory uri) {
55+
return "";
56+
}
57+
58+
function getPublishedUriFromCompilerUri(string memory)
59+
external
60+
pure
61+
returns (string[] memory publishedMetadataUris)
62+
{
63+
return new string[](0);
64+
}
65+
}

contracts/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@thirdweb-dev/contracts",
33
"description": "Collection of smart contracts deployable via the thirdweb SDK, dashboard and CLI",
4-
"version": "3.0.3",
4+
"version": "3.0.4-3",
55
"license": "Apache-2.0",
66
"repository": {
77
"type": "git",

contracts/signature-drop/SignatureDrop.sol

+9-6
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ contract SignatureDrop is
127127
}
128128

129129
function contractVersion() external pure returns (uint8) {
130-
return uint8(2);
130+
return uint8(3);
131131
}
132132

133133
/*///////////////////////////////////////////////////////////////
@@ -141,13 +141,16 @@ contract SignatureDrop is
141141
function lazyMint(
142142
uint256 _amount,
143143
string calldata _baseURIForTokens,
144-
bytes calldata _encryptedBaseURI
144+
bytes calldata _data
145145
) public override onlyRole(minterRole) returns (uint256 batchId) {
146-
if (_encryptedBaseURI.length != 0) {
147-
_setEncryptedBaseURI(nextTokenIdToLazyMint + _amount, _encryptedBaseURI);
146+
if (_data.length > 0) {
147+
(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(_data, (bytes, bytes32));
148+
if (encryptedURI.length != 0 && provenanceHash != "") {
149+
_setEncryptedData(nextTokenIdToLazyMint + _amount, _data);
150+
}
148151
}
149152

150-
return super.lazyMint(_amount, _baseURIForTokens, _encryptedBaseURI);
153+
return super.lazyMint(_amount, _baseURIForTokens, _data);
151154
}
152155

153156
/// @dev Lets an account with `MINTER_ROLE` reveal the URI for a batch of 'delayed-reveal' NFTs.
@@ -159,7 +162,7 @@ contract SignatureDrop is
159162
uint256 batchId = getBatchIdAtIndex(_index);
160163
revealedURI = getRevealURI(batchId, _key);
161164

162-
_setEncryptedBaseURI(batchId, "");
165+
_setEncryptedData(batchId, "");
163166
_setBaseURI(batchId, revealedURI);
164167

165168
emit TokenURIRevealed(_index, revealedURI);

docs/DelayedReveal.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ Encrypt/decrypt data on chain.
3333
|---|---|---|
3434
| result | bytes | Output after encryption/decryption of given data.
3535

36-
### encryptedBaseURI
36+
### encryptedData
3737

3838
```solidity
39-
function encryptedBaseURI(uint256) external view returns (bytes)
39+
function encryptedData(uint256) external view returns (bytes)
4040
```
4141

4242

4343

44-
*Mapping from id of a batch of tokens =&gt; to encrypted base URI for the respective batch of tokens.*
44+
*Mapping from tokenId of a batch of tokens =&gt; to delayed reveal data.*
4545

4646
#### Parameters
4747

docs/DropERC721.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,10 @@ function encryptDecrypt(bytes data, bytes key) external pure returns (bytes resu
217217
|---|---|---|
218218
| result | bytes | undefined
219219

220-
### encryptedBaseURI
220+
### encryptedData
221221

222222
```solidity
223-
function encryptedBaseURI(uint256) external view returns (bytes)
223+
function encryptedData(uint256) external view returns (bytes)
224224
```
225225

226226

@@ -580,7 +580,7 @@ function isTrustedForwarder(address forwarder) external view returns (bool)
580580
### lazyMint
581581

582582
```solidity
583-
function lazyMint(uint256 _amount, string _baseURIForTokens, bytes _encryptedBaseURI) external nonpayable
583+
function lazyMint(uint256 _amount, string _baseURIForTokens, bytes _data) external nonpayable
584584
```
585585

586586

@@ -593,7 +593,7 @@ function lazyMint(uint256 _amount, string _baseURIForTokens, bytes _encryptedBas
593593
|---|---|---|
594594
| _amount | uint256 | undefined
595595
| _baseURIForTokens | string | undefined
596-
| _encryptedBaseURI | bytes | undefined
596+
| _data | bytes | undefined
597597

598598
### maxTotalSupply
599599

0 commit comments

Comments
 (0)