Skip to content

Commit e3e60e8

Browse files
Krishang NadgaudaKrishang Nadgauda
authored andcommitted
revert Token contracts interfaces to specific MintRequest structs
1 parent 543dbfd commit e3e60e8

File tree

12 files changed

+988
-102
lines changed

12 files changed

+988
-102
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.11;
3+
4+
import "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";
5+
6+
/**
7+
* `SignatureMint1155` is an ERC 1155 contract. It lets anyone mint NFTs by producing a mint request
8+
* and a signature (produced by an account with MINTER_ROLE, signing the mint request).
9+
*/
10+
interface ITokenERC1155 is IERC1155Upgradeable {
11+
/**
12+
* @notice The body of a request to mint NFTs.
13+
*
14+
* @param to The receiver of the NFTs to mint.
15+
* @param royaltyRecipient The recipient of the minted NFT's secondary sales royalties.
16+
* @param primarySaleRecipient The recipient of the minted NFT's primary sales proceeds.
17+
* @param tokenId Optional: specify only if not first mint.
18+
* @param uri The URI of the NFT to mint.
19+
* @param quantity The quantity of NFTs to mint.
20+
* @param pricePerToken Price to pay for minting with the signature.
21+
* @param currency The currency in which the price per token must be paid.
22+
* @param validityStartTimestamp The unix timestamp after which the request is valid.
23+
* @param validityEndTimestamp The unix timestamp after which the request expires.
24+
* @param uid A unique identifier for the request.
25+
*/
26+
struct MintRequest {
27+
address to;
28+
address royaltyRecipient;
29+
uint256 royaltyBps;
30+
address primarySaleRecipient;
31+
uint256 tokenId;
32+
string uri;
33+
uint256 quantity;
34+
uint256 pricePerToken;
35+
address currency;
36+
uint128 validityStartTimestamp;
37+
uint128 validityEndTimestamp;
38+
bytes32 uid;
39+
}
40+
41+
/// @dev Emitted when an account with MINTER_ROLE mints an NFT.
42+
event TokensMinted(address indexed mintedTo, uint256 indexed tokenIdMinted, string uri, uint256 quantityMinted);
43+
44+
/// @dev Emitted when tokens are minted.
45+
event TokensMintedWithSignature(
46+
address indexed signer,
47+
address indexed mintedTo,
48+
uint256 indexed tokenIdMinted,
49+
MintRequest mintRequest
50+
);
51+
52+
/**
53+
* @notice Verifies that a mint request is signed by an account holding
54+
* MINTER_ROLE (at the time of the function call).
55+
*
56+
* @param req The mint request.
57+
* @param signature The signature produced by an account signing the mint request.
58+
*
59+
* returns (success, signer) Result of verification and the recovered address.
60+
*/
61+
function verify(MintRequest calldata req, bytes calldata signature)
62+
external
63+
view
64+
returns (bool success, address signer);
65+
66+
/**
67+
* @notice Lets an account with MINTER_ROLE mint an NFT.
68+
*
69+
* @param to The address to mint the NFT to.
70+
* @param tokenId The tokenId of the NFTs to mint
71+
* @param uri The URI to assign to the NFT.
72+
* @param amount The number of copies of the NFT to mint.
73+
*
74+
*/
75+
function mintTo(
76+
address to,
77+
uint256 tokenId,
78+
string calldata uri,
79+
uint256 amount
80+
) external;
81+
82+
/**
83+
* @notice Mints an NFT according to the provided mint request.
84+
*
85+
* @param req The mint request.
86+
* @param signature he signature produced by an account signing the mint request.
87+
*/
88+
function mintWithSignature(MintRequest calldata req, bytes calldata signature) external payable;
89+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.11;
3+
4+
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
5+
6+
interface ITokenERC20 is IERC20MetadataUpgradeable {
7+
/**
8+
* @notice The body of a request to mint tokens.
9+
*
10+
* @param to The receiver of the tokens to mint.
11+
* @param primarySaleRecipient The receiver of the primary sale funds from the mint.
12+
* @param quantity The quantity of tpkens to mint.
13+
* @param price Price to pay for minting with the signature.
14+
* @param currency The currency in which the price per token must be paid.
15+
* @param validityStartTimestamp The unix timestamp after which the request is valid.
16+
* @param validityEndTimestamp The unix timestamp after which the request expires.
17+
* @param uid A unique identifier for the request.
18+
*/
19+
struct MintRequest {
20+
address to;
21+
address primarySaleRecipient;
22+
uint256 quantity;
23+
uint256 price;
24+
address currency;
25+
uint128 validityStartTimestamp;
26+
uint128 validityEndTimestamp;
27+
bytes32 uid;
28+
}
29+
30+
/// @dev Emitted when an account with MINTER_ROLE mints an NFT.
31+
event TokensMinted(address indexed mintedTo, uint256 quantityMinted);
32+
33+
/// @dev Emitted when tokens are minted.
34+
event TokensMintedWithSignature(address indexed signer, address indexed mintedTo, MintRequest mintRequest);
35+
36+
/**
37+
* @notice Verifies that a mint request is signed by an account holding
38+
* MINTER_ROLE (at the time of the function call).
39+
*
40+
* @param req The mint request.
41+
* @param signature The signature produced by an account signing the mint request.
42+
*
43+
* returns (success, signer) Result of verification and the recovered address.
44+
*/
45+
function verify(MintRequest calldata req, bytes calldata signature)
46+
external
47+
view
48+
returns (bool success, address signer);
49+
50+
/**
51+
* @dev Creates `amount` new tokens for `to`.
52+
*
53+
* See {ERC20-_mint}.
54+
*
55+
* Requirements:
56+
*
57+
* - the caller must have the `MINTER_ROLE`.
58+
*/
59+
function mintTo(address to, uint256 amount) external;
60+
61+
/**
62+
* @notice Mints an NFT according to the provided mint request.
63+
*
64+
* @param req The mint request.
65+
* @param signature he signature produced by an account signing the mint request.
66+
*/
67+
function mintWithSignature(MintRequest calldata req, bytes calldata signature) external payable;
68+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.11;
3+
4+
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
5+
6+
/**
7+
* `SignatureMint` is an ERC 721 contract. It lets anyone mint NFTs by producing a mint request
8+
* and a signature (produced by an account with MINTER_ROLE, signing the mint request).
9+
*/
10+
interface ITokenERC721 is IERC721Upgradeable {
11+
/**
12+
* @notice The body of a request to mint NFTs.
13+
*
14+
* @param to The receiver of the NFTs to mint.
15+
* @param uri The URI of the NFT to mint.
16+
* @param price Price to pay for minting with the signature.
17+
* @param currency The currency in which the price per token must be paid.
18+
* @param validityStartTimestamp The unix timestamp after which the request is valid.
19+
* @param validityEndTimestamp The unix timestamp after which the request expires.
20+
* @param uid A unique identifier for the request.
21+
*/
22+
struct MintRequest {
23+
address to;
24+
address royaltyRecipient;
25+
uint256 royaltyBps;
26+
address primarySaleRecipient;
27+
string uri;
28+
uint256 price;
29+
address currency;
30+
uint128 validityStartTimestamp;
31+
uint128 validityEndTimestamp;
32+
bytes32 uid;
33+
}
34+
35+
/// @dev Emitted when an account with MINTER_ROLE mints an NFT.
36+
event TokensMinted(address indexed mintedTo, uint256 indexed tokenIdMinted, string uri);
37+
38+
/// @dev Emitted when tokens are minted.
39+
event TokensMintedWithSignature(
40+
address indexed signer,
41+
address indexed mintedTo,
42+
uint256 indexed tokenIdMinted,
43+
MintRequest mintRequest
44+
);
45+
46+
/// @dev Emitted when accrued royalties are withdrawn from the contract.
47+
event FundsWithdrawn(
48+
address indexed paymentReceiver,
49+
address feeRecipient,
50+
uint256 totalAmount,
51+
uint256 feeCollected
52+
);
53+
54+
/**
55+
* @notice Verifies that a mint request is signed by an account holding
56+
* MINTER_ROLE (at the time of the function call).
57+
*
58+
* @param req The mint request.
59+
* @param signature The signature produced by an account signing the mint request.
60+
*
61+
* returns (success, signer) Result of verification and the recovered address.
62+
*/
63+
function verify(MintRequest calldata req, bytes calldata signature)
64+
external
65+
view
66+
returns (bool success, address signer);
67+
68+
/**
69+
* @notice Lets an account with MINTER_ROLE mint an NFT.
70+
*
71+
* @param to The address to mint the NFT to.
72+
* @param uri The URI to assign to the NFT.
73+
*
74+
* @return tokenId of the NFT minted.
75+
*/
76+
function mintTo(address to, string calldata uri) external returns (uint256);
77+
78+
/**
79+
* @notice Mints an NFT according to the provided mint request.
80+
*
81+
* @param req The mint request.
82+
* @param signature he signature produced by an account signing the mint request.
83+
*/
84+
function mintWithSignature(MintRequest calldata req, bytes calldata signature) external payable returns (uint256);
85+
}

contracts/token/TokenERC1155.sol

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
pragma solidity ^0.8.11;
33

44
// Interface
5-
import "../feature/interface/IMintableERC1155.sol";
6-
import "../feature/interface/IBurnableERC1155.sol";
7-
import "../feature/SignatureMintUpgradeable.sol";
5+
import { ITokenERC1155 } from "../interfaces/token/ITokenERC1155.sol";
86

97
import "../interfaces/IThirdwebContract.sol";
108
import "../feature/interface/IThirdwebPlatformFee.sol";
@@ -15,6 +13,10 @@ import "../feature/interface/IThirdwebOwnable.sol";
1513
// Token
1614
import "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol";
1715

16+
// Signature utils
17+
import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
18+
import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";
19+
1820
// Access Control + security
1921
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
2022
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
@@ -39,15 +41,15 @@ contract TokenERC1155 is
3941
IThirdwebRoyalty,
4042
IThirdwebPrimarySale,
4143
IThirdwebPlatformFee,
44+
EIP712Upgradeable,
4245
ReentrancyGuardUpgradeable,
4346
ERC2771ContextUpgradeable,
4447
MulticallUpgradeable,
4548
AccessControlEnumerableUpgradeable,
4649
ERC1155Upgradeable,
47-
IMintableERC1155,
48-
IBurnableERC1155,
49-
SignatureMintUpgradeable
50+
ITokenERC1155
5051
{
52+
using ECDSAUpgradeable for bytes32;
5153
using StringsUpgradeable for uint256;
5254

5355
bytes32 private constant MODULE_TYPE = bytes32("TokenERC1155");
@@ -59,8 +61,15 @@ contract TokenERC1155 is
5961
// Token symbol
6062
string public symbol;
6163

64+
bytes32 private constant TYPEHASH =
65+
keccak256(
66+
"MintRequest(address to,address royaltyRecipient,uint256 royaltyBps,address primarySaleRecipient,uint256 tokenId,string uri,uint256 quantity,uint256 pricePerToken,address currency,uint128 validityStartTimestamp,uint128 validityEndTimestamp,bytes32 uid)"
67+
);
68+
6269
/// @dev Only TRANSFER_ROLE holders can have tokens transferred from or to them, during restricted transfers.
6370
bytes32 private constant TRANSFER_ROLE = keccak256("TRANSFER_ROLE");
71+
/// @dev Only MINTER_ROLE holders can sign off on `MintRequest`s.
72+
bytes32 private constant MINTER_ROLE = keccak256("MINTER_ROLE");
6473

6574
/// @dev Max bps in the thirdweb system
6675
uint256 private constant MAX_BPS = 10_000;
@@ -95,6 +104,9 @@ contract TokenERC1155 is
95104
/// @dev Contract level metadata.
96105
string public contractURI;
97106

107+
/// @dev Mapping from mint request UID => whether the mint request is processed.
108+
mapping(bytes32 => bool) private minted;
109+
98110
mapping(uint256 => string) private _tokenURI;
99111

100112
/// @dev Token ID => total circulating supply of tokens with that ID.
@@ -125,9 +137,9 @@ contract TokenERC1155 is
125137
) external initializer {
126138
// Initialize inherited contracts, most base-like -> most derived.
127139
__ReentrancyGuard_init();
140+
__EIP712_init("TokenERC1155", "1");
128141
__ERC2771Context_init(_trustedForwarders);
129142
__ERC1155_init("");
130-
__SignatureMint_init("TokenERC1155", "1", _defaultAdmin);
131143

132144
// Initialize this contract's state.
133145
name = _name;
@@ -165,8 +177,14 @@ contract TokenERC1155 is
165177
return hasRole(DEFAULT_ADMIN_ROLE, _owner) ? _owner : address(0);
166178
}
167179

180+
/// @dev Verifies that a mint request is signed by an account holding MINTER_ROLE (at the time of the function call).
181+
function verify(MintRequest calldata _req, bytes calldata _signature) public view returns (bool, address) {
182+
address signer = recoverAddress(_req, _signature);
183+
return (!minted[_req.uid] && hasRole(MINTER_ROLE, signer), signer);
184+
}
185+
168186
/// @dev Returns the URI for a tokenId
169-
function uri(uint256 _tokenId) public view override(ERC1155Upgradeable) returns (string memory) {
187+
function uri(uint256 _tokenId) public view override returns (string memory) {
170188
return _tokenURI[_tokenId];
171189
}
172190

@@ -334,6 +352,31 @@ contract TokenERC1155 is
334352
emit TokensMinted(_to, _tokenId, _tokenURI[_tokenId], _amount);
335353
}
336354

355+
/// @dev Returns the address of the signer of the mint request.
356+
function recoverAddress(MintRequest calldata _req, bytes calldata _signature) internal view returns (address) {
357+
return _hashTypedDataV4(keccak256(_encodeRequest(_req))).recover(_signature);
358+
}
359+
360+
/// @dev Resolves 'stack too deep' error in `recoverAddress`.
361+
function _encodeRequest(MintRequest calldata _req) internal pure returns (bytes memory) {
362+
return
363+
abi.encode(
364+
TYPEHASH,
365+
_req.to,
366+
_req.royaltyRecipient,
367+
_req.royaltyBps,
368+
_req.primarySaleRecipient,
369+
_req.tokenId,
370+
keccak256(bytes(_req.uri)),
371+
_req.quantity,
372+
_req.pricePerToken,
373+
_req.currency,
374+
_req.validityStartTimestamp,
375+
_req.validityEndTimestamp,
376+
_req.uid
377+
);
378+
}
379+
337380
/// @dev Verifies that a mint request is valid.
338381
function verifyRequest(MintRequest calldata _req, bytes calldata _signature) internal returns (address) {
339382
(bool success, address signer) = verify(_req, _signature);
@@ -443,7 +486,7 @@ contract TokenERC1155 is
443486
public
444487
view
445488
virtual
446-
override(AccessControlEnumerableUpgradeable, ERC1155Upgradeable)
489+
override(AccessControlEnumerableUpgradeable, ERC1155Upgradeable, IERC165Upgradeable)
447490
returns (bool)
448491
{
449492
return

0 commit comments

Comments
 (0)