22pragma 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
97import "../interfaces/IThirdwebContract.sol " ;
108import "../feature/interface/IThirdwebPlatformFee.sol " ;
@@ -15,6 +13,10 @@ import "../feature/interface/IThirdwebOwnable.sol";
1513// Token
1614import "@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
1921import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol " ;
2022import "@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