Skip to content

Commit

Permalink
Con215 - Update to Delayed Reveal functionality (#204)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
3 people authored Aug 12, 2022
1 parent 97d7628 commit 0532c04
Show file tree
Hide file tree
Showing 28 changed files with 644 additions and 243 deletions.
17 changes: 10 additions & 7 deletions contracts/base/ERC721DelayedReveal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,22 @@ contract ERC721DelayedReveal is ERC721LazyMint, DelayedReveal {
* @param _amount The number of NFTs to lazy mint.
* @param _baseURIForTokens The placeholder base URI for the 'n' number of NFTs being lazy minted, where the
* metadata for each of those NFTs is `${baseURIForTokens}/${tokenId}`.
* @param _encryptedBaseURI The encrypted base URI for the batch of NFTs being lazy minted.
* @param _data The encrypted base URI + provenance hash for the batch of NFTs being lazy minted.
* @return batchId A unique integer identifier for the batch of NFTs lazy minted together.
*/
function lazyMint(
uint256 _amount,
string calldata _baseURIForTokens,
bytes calldata _encryptedBaseURI
) public virtual override returns (uint256 batchId) {
if (_encryptedBaseURI.length != 0) {
_setEncryptedBaseURI(nextTokenIdToLazyMint + _amount, _encryptedBaseURI);
bytes calldata _data
) public override returns (uint256 batchId) {
if (_data.length > 0) {
(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(_data, (bytes, bytes32));
if (encryptedURI.length != 0 && provenanceHash != "") {
_setEncryptedData(nextTokenIdToLazyMint + _amount, _data);
}
}

return super.lazyMint(_amount, _baseURIForTokens, _encryptedBaseURI);
return super.lazyMint(_amount, _baseURIForTokens, _data);
}

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

_setEncryptedBaseURI(batchId, "");
_setEncryptedData(batchId, "");
_setBaseURI(batchId, revealedURI);

emit TokenURIRevealed(_index, revealedURI);
Expand Down
17 changes: 10 additions & 7 deletions contracts/base/ERC721Drop.sol
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,22 @@ contract ERC721Drop is ERC721SignatureMint, LazyMint, DelayedReveal, DropSingleP
* @param _amount The number of NFTs to lazy mint.
* @param _baseURIForTokens The placeholder base URI for the 'n' number of NFTs being lazy minted, where the
* metadata for each of those NFTs is `${baseURIForTokens}/${tokenId}`.
* @param _encryptedBaseURI The encrypted base URI for the batch of NFTs being lazy minted.
* @param _data The encrypted base URI + provenance hash for the batch of NFTs being lazy minted.
* @return batchId A unique integer identifier for the batch of NFTs lazy minted together.
*/
function lazyMint(
uint256 _amount,
string calldata _baseURIForTokens,
bytes calldata _encryptedBaseURI
) public virtual override returns (uint256 batchId) {
if (_encryptedBaseURI.length != 0) {
_setEncryptedBaseURI(nextTokenIdToLazyMint + _amount, _encryptedBaseURI);
bytes calldata _data
) public override returns (uint256 batchId) {
if (_data.length > 0) {
(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(_data, (bytes, bytes32));
if (encryptedURI.length != 0 && provenanceHash != "") {
_setEncryptedData(nextTokenIdToLazyMint + _amount, _data);
}
}

return LazyMint.lazyMint(_amount, _baseURIForTokens, _encryptedBaseURI);
return LazyMint.lazyMint(_amount, _baseURIForTokens, _data);
}

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

_setEncryptedBaseURI(batchId, "");
_setEncryptedData(batchId, "");
_setBaseURI(batchId, revealedURI);

emit TokenURIRevealed(_index, revealedURI);
Expand Down
26 changes: 17 additions & 9 deletions contracts/drop/DropERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ contract DropERC721 is
//////////////////////////////////////////////////////////////*/

bytes32 private constant MODULE_TYPE = bytes32("DropERC721");
uint256 private constant VERSION = 2;
uint256 private constant VERSION = 3;

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

/// @dev Mapping from address => total number of NFTs a wallet has claimed.
mapping(address => uint256) public walletClaimCount;
Expand Down Expand Up @@ -193,7 +193,7 @@ contract DropERC721 is
function tokenURI(uint256 _tokenId) public view override returns (string memory) {
for (uint256 i = 0; i < baseURIIndices.length; i += 1) {
if (_tokenId < baseURIIndices[i]) {
if (encryptedBaseURI[baseURIIndices[i]].length != 0) {
if (encryptedData[baseURIIndices[i]].length != 0) {
return string(abi.encodePacked(baseURI[baseURIIndices[i]], "0"));
} else {
return string(abi.encodePacked(baseURI[baseURIIndices[i]], _tokenId.toString()));
Expand Down Expand Up @@ -238,7 +238,7 @@ contract DropERC721 is
function lazyMint(
uint256 _amount,
string calldata _baseURIForTokens,
bytes calldata _encryptedBaseURI
bytes calldata _data
) external onlyRole(MINTER_ROLE) {
uint256 startId = nextTokenIdToMint;
uint256 baseURIIndex = startId + _amount;
Expand All @@ -247,11 +247,15 @@ contract DropERC721 is
baseURI[baseURIIndex] = _baseURIForTokens;
baseURIIndices.push(baseURIIndex);

if (_encryptedBaseURI.length != 0) {
encryptedBaseURI[baseURIIndex] = _encryptedBaseURI;
if (_data.length > 0) {
(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(_data, (bytes, bytes32));

if (encryptedURI.length != 0 && provenanceHash != "") {
encryptedData[baseURIIndex] = _data;
}
}

emit TokensLazyMinted(startId, startId + _amount - 1, _baseURIForTokens, _encryptedBaseURI);
emit TokensLazyMinted(startId, startId + _amount - 1, _baseURIForTokens, _data);
}

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

uint256 _index = baseURIIndices[index];
bytes memory encryptedURI = encryptedBaseURI[_index];
bytes memory data = encryptedData[_index];
(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(data, (bytes, bytes32));

require(encryptedURI.length != 0, "nothing to reveal.");

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

require(keccak256(abi.encodePacked(revealedURI, _key, block.chainid)) == provenanceHash, "Incorrect key");

baseURI[_index] = revealedURI;
delete encryptedBaseURI[_index];
delete encryptedData[_index];

emit NFTRevealed(_index, revealedURI);

Expand Down
20 changes: 12 additions & 8 deletions contracts/extension/DelayedReveal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import "./interface/IDelayedReveal.sol";
*/

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

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

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

(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(data, (bytes, bytes32));

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

require(keccak256(abi.encodePacked(revealedURI, _key, block.chainid)) == provenanceHash, "Incorrect key");
}

/**
Expand Down Expand Up @@ -89,6 +93,6 @@ abstract contract DelayedReveal is IDelayedReveal {
* @param _batchId ID of a batch of NFTs.
*/
function isEncryptedBatch(uint256 _batchId) public view returns (bool) {
return encryptedBaseURI[_batchId].length > 0;
return encryptedData[_batchId].length > 0;
}
}
36 changes: 36 additions & 0 deletions contracts/extension/interface/IDelayedRevealDeprecated.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

// [ DEPRECATED CONTRACT: use `contracts/extension/interface/IDelayedReveal.sol` instead ]

/**
* Thirdweb's `DelayedReveal` is a contract extension for base NFT contracts. It lets you create batches of
* 'delayed-reveal' NFTs. You can learn more about the usage of delayed reveal NFTs here - https://blog.thirdweb.com/delayed-reveal-nfts
*/

interface IDelayedRevealDeprecated {
/// @dev Emitted when tokens are revealed.
event TokenURIRevealed(uint256 indexed index, string revealedURI);

/// @dev Returns the encrypted base URI associated with the given identifier.
function encryptedBaseURI(uint256 identifier) external view returns (bytes memory);

/**
* @notice Reveals a batch of delayed reveal NFTs.
*
* @param identifier The ID for the batch of delayed-reveal NFTs to reveal.
*
* @param key The key with which the base URI for the relevant batch of NFTs was encrypted.
*/
function reveal(uint256 identifier, bytes calldata key) external returns (string memory revealedURI);

/**
* @notice Performs XOR encryption/decryption.
*
* @param data The data to encrypt. In the case of delayed-reveal NFTs, this is the "revealed" state
* base URI of the relevant batch of NFTs.
*
* @param key The key with which to encrypt data
*/
function encryptDecrypt(bytes memory data, bytes calldata key) external pure returns (bytes memory result);
}
65 changes: 65 additions & 0 deletions contracts/mock/MockContractPublisher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

import "../interfaces/IContractPublisher.sol";

// solhint-disable const-name-snakecase
contract MockContractPublisher is IContractPublisher {
function getAllPublishedContracts(address)
external
pure
override
returns (CustomContractInstance[] memory published)
{
CustomContractInstance[] memory mocks = new CustomContractInstance[](1);
mocks[0] = CustomContractInstance(
"MockContract",
123,
"ipfs://mock",
0x0000000000000000000000000000000000000000000000000000000000000001,
address(0x0000000000000000000000000000000000000000)
);
return mocks;
}

function getPublishedContractVersions(address, string memory)
external
pure
returns (CustomContractInstance[] memory published)
{
return new CustomContractInstance[](0);
}

function getPublishedContract(address, string memory)
external
pure
returns (CustomContractInstance memory published)
{
return CustomContractInstance("", 0, "", "", address(0));
}

function publishContract(
address publisher,
string memory contractId,
string memory publishMetadataUri,
string memory compilerMetadataUri,
bytes32 bytecodeHash,
address implementation
) external {}

function unpublishContract(address publisher, string memory contractId) external {}

function setPublisherProfileUri(address, string memory) external {}

function getPublisherProfileUri(address) external pure returns (string memory uri) {
return "";
}

function getPublishedUriFromCompilerUri(string memory)
external
pure
returns (string[] memory publishedMetadataUris)
{
return new string[](0);
}
}
2 changes: 1 addition & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/contracts",
"description": "Collection of smart contracts deployable via the thirdweb SDK, dashboard and CLI",
"version": "3.0.3",
"version": "3.0.4-3",
"license": "Apache-2.0",
"repository": {
"type": "git",
Expand Down
15 changes: 9 additions & 6 deletions contracts/signature-drop/SignatureDrop.sol
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ contract SignatureDrop is
}

function contractVersion() external pure returns (uint8) {
return uint8(2);
return uint8(3);
}

/*///////////////////////////////////////////////////////////////
Expand All @@ -141,13 +141,16 @@ contract SignatureDrop is
function lazyMint(
uint256 _amount,
string calldata _baseURIForTokens,
bytes calldata _encryptedBaseURI
bytes calldata _data
) public override onlyRole(minterRole) returns (uint256 batchId) {
if (_encryptedBaseURI.length != 0) {
_setEncryptedBaseURI(nextTokenIdToLazyMint + _amount, _encryptedBaseURI);
if (_data.length > 0) {
(bytes memory encryptedURI, bytes32 provenanceHash) = abi.decode(_data, (bytes, bytes32));
if (encryptedURI.length != 0 && provenanceHash != "") {
_setEncryptedData(nextTokenIdToLazyMint + _amount, _data);
}
}

return super.lazyMint(_amount, _baseURIForTokens, _encryptedBaseURI);
return super.lazyMint(_amount, _baseURIForTokens, _data);
}

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

_setEncryptedBaseURI(batchId, "");
_setEncryptedData(batchId, "");
_setBaseURI(batchId, revealedURI);

emit TokenURIRevealed(_index, revealedURI);
Expand Down
6 changes: 3 additions & 3 deletions docs/DelayedReveal.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ Encrypt/decrypt data on chain.
|---|---|---|
| result | bytes | Output after encryption/decryption of given data.

### encryptedBaseURI
### encryptedData

```solidity
function encryptedBaseURI(uint256) external view returns (bytes)
function encryptedData(uint256) external view returns (bytes)
```



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

#### Parameters

Expand Down
8 changes: 4 additions & 4 deletions docs/DropERC721.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,10 @@ function encryptDecrypt(bytes data, bytes key) external pure returns (bytes resu
|---|---|---|
| result | bytes | undefined

### encryptedBaseURI
### encryptedData

```solidity
function encryptedBaseURI(uint256) external view returns (bytes)
function encryptedData(uint256) external view returns (bytes)
```


Expand Down Expand Up @@ -580,7 +580,7 @@ function isTrustedForwarder(address forwarder) external view returns (bool)
### lazyMint

```solidity
function lazyMint(uint256 _amount, string _baseURIForTokens, bytes _encryptedBaseURI) external nonpayable
function lazyMint(uint256 _amount, string _baseURIForTokens, bytes _data) external nonpayable
```


Expand All @@ -593,7 +593,7 @@ function lazyMint(uint256 _amount, string _baseURIForTokens, bytes _encryptedBas
|---|---|---|
| _amount | uint256 | undefined
| _baseURIForTokens | string | undefined
| _encryptedBaseURI | bytes | undefined
| _data | bytes | undefined

### maxTotalSupply

Expand Down
Loading

0 comments on commit 0532c04

Please sign in to comment.