11// SPDX-License-Identifier: Apache-2.0
22pragma solidity ^ 0.8.20 ;
33
4+ import {OwnableRoles} from "@solady/auth/OwnableRoles.sol " ;
45import {ERC1155 } from "@solady/tokens/ERC1155.sol " ;
6+
7+ import {ECDSA} from "@solady/utils/ECDSA.sol " ;
8+ import {EIP712} from "@solady/utils/EIP712.sol " ;
59import {Initializable} from "@solady/utils/Initializable.sol " ;
610import {Multicallable} from "@solady/utils/Multicallable.sol " ;
711
812import {Core} from "../../Core.sol " ;
13+ import {Role} from "../../Role.sol " ;
914
1015import {BeforeApproveForAllCallback} from "../../callback/BeforeApproveForAllCallback.sol " ;
1116import {BeforeBatchTransferCallbackERC1155} from "../../callback/BeforeBatchTransferCallbackERC1155.sol " ;
1217import {BeforeBurnCallbackERC1155} from "../../callback/BeforeBurnCallbackERC1155.sol " ;
1318import {BeforeMintCallbackERC1155} from "../../callback/BeforeMintCallbackERC1155.sol " ;
19+ import {BeforeMintWithSignatureCallbackERC1155} from "../../callback/BeforeMintWithSignatureCallbackERC1155.sol " ;
1420import {BeforeTransferCallbackERC1155} from "../../callback/BeforeTransferCallbackERC1155.sol " ;
21+ import {UpdateMetadataCallbackERC1155} from "../../callback/UpdateMetadataCallbackERC1155.sol " ;
1522
1623import {OnTokenURICallback} from "../../callback/OnTokenURICallback.sol " ;
1724
18- contract ERC1155CoreInitializable is ERC1155 , Core , Multicallable , Initializable {
25+ contract ERC1155CoreInitializable is ERC1155 , Core , Multicallable , Initializable , EIP712 {
26+
27+ using ECDSA for bytes32 ;
28+
29+ /*//////////////////////////////////////////////////////////////
30+ CONSTANTS
31+ //////////////////////////////////////////////////////////////*/
32+
33+ bytes32 private constant TYPEHASH_SIGNATURE_MINT_ERC1155 =
34+ keccak256 ("MintRequestERC1155(address to,uint256 tokenId,uint256 value,string baseURI,bytes data) " );
1935
2036 /*//////////////////////////////////////////////////////////////
2137 STORAGE
@@ -40,6 +56,12 @@ contract ERC1155CoreInitializable is ERC1155, Core, Multicallable, Initializable
4056 /// @notice Emitted when the contract URI is updated.
4157 event ContractURIUpdated ();
4258
59+ /*//////////////////////////////////////////////////////////////
60+ ERRORS
61+ //////////////////////////////////////////////////////////////*/
62+
63+ error SignatureMintUnauthorized ();
64+
4365 /*//////////////////////////////////////////////////////////////
4466 CONSTRUCTOR & INITIALIZER
4567 //////////////////////////////////////////////////////////////*/
@@ -128,29 +150,37 @@ contract ERC1155CoreInitializable is ERC1155, Core, Multicallable, Initializable
128150 override
129151 returns (SupportedCallbackFunction[] memory supportedCallbackFunctions )
130152 {
131- supportedCallbackFunctions = new SupportedCallbackFunction [](6 );
153+ supportedCallbackFunctions = new SupportedCallbackFunction [](8 );
132154 supportedCallbackFunctions[0 ] = SupportedCallbackFunction ({
133155 selector: BeforeMintCallbackERC1155.beforeMintERC1155.selector ,
134156 mode: CallbackMode.REQUIRED
135157 });
136158 supportedCallbackFunctions[1 ] = SupportedCallbackFunction ({
159+ selector: BeforeMintWithSignatureCallbackERC1155.beforeMintWithSignatureERC1155.selector ,
160+ mode: CallbackMode.REQUIRED
161+ });
162+ supportedCallbackFunctions[2 ] = SupportedCallbackFunction ({
137163 selector: BeforeTransferCallbackERC1155.beforeTransferERC1155.selector ,
138164 mode: CallbackMode.OPTIONAL
139165 });
140- supportedCallbackFunctions[2 ] = SupportedCallbackFunction ({
166+ supportedCallbackFunctions[3 ] = SupportedCallbackFunction ({
141167 selector: BeforeBatchTransferCallbackERC1155.beforeBatchTransferERC1155.selector ,
142168 mode: CallbackMode.OPTIONAL
143169 });
144- supportedCallbackFunctions[3 ] = SupportedCallbackFunction ({
170+ supportedCallbackFunctions[4 ] = SupportedCallbackFunction ({
145171 selector: BeforeBurnCallbackERC1155.beforeBurnERC1155.selector ,
146172 mode: CallbackMode.OPTIONAL
147173 });
148- supportedCallbackFunctions[4 ] = SupportedCallbackFunction ({
174+ supportedCallbackFunctions[5 ] = SupportedCallbackFunction ({
149175 selector: BeforeApproveForAllCallback.beforeApproveForAll.selector ,
150176 mode: CallbackMode.OPTIONAL
151177 });
152- supportedCallbackFunctions[5 ] =
178+ supportedCallbackFunctions[6 ] =
153179 SupportedCallbackFunction ({selector: OnTokenURICallback.onTokenURI.selector , mode: CallbackMode.REQUIRED});
180+ supportedCallbackFunctions[7 ] = SupportedCallbackFunction ({
181+ selector: UpdateMetadataCallbackERC1155.updateMetadataERC1155.selector ,
182+ mode: CallbackMode.REQUIRED
183+ });
154184 }
155185
156186 /*//////////////////////////////////////////////////////////////
@@ -172,15 +202,57 @@ contract ERC1155CoreInitializable is ERC1155, Core, Multicallable, Initializable
172202 * @param to The address to mint the token to.
173203 * @param tokenId The tokenId to mint.
174204 * @param value The amount of tokens to mint.
205+ * @param baseURI The base URI for the token metadata.
175206 * @param data ABI encoded data to pass to the beforeMint hook.
176207 */
177- function mint (address to , uint256 tokenId , uint256 value , bytes memory data ) external payable {
208+ function mint (address to , uint256 tokenId , uint256 value , string calldata baseURI , bytes memory data )
209+ external
210+ payable
211+ {
212+ if (bytes (baseURI).length > 0 ) {
213+ _updateMetadata (to, tokenId, value, baseURI);
214+ }
178215 _beforeMint (to, tokenId, value, data);
179216
180217 _totalSupply[tokenId] += value;
181218 _mint (to, tokenId, value, "" );
182219 }
183220
221+ /**
222+ * @notice Mints tokens with a signature. Calls the beforeMintWithSignature hook.
223+ * @dev Reverts if beforeMintWithSignature hook is absent or unsuccessful.
224+ * @param to The address to mint the token to.
225+ * @param tokenId The tokenId to mint.
226+ * @param value The amount of tokens to mint.
227+ * @param baseURI The base URI for the token metadata.
228+ * @param data ABI encoded data to pass to the beforeMintWithSignature hook.
229+ * @param signature The signature produced from signing the minting request.
230+ */
231+ function mintWithSignature (
232+ address to ,
233+ uint256 tokenId ,
234+ uint256 value ,
235+ string calldata baseURI ,
236+ bytes calldata data ,
237+ bytes memory signature
238+ ) external payable {
239+ address signer = _hashTypedData (
240+ keccak256 (abi.encode (TYPEHASH_SIGNATURE_MINT_ERC1155, to, tokenId, value, keccak256 (bytes (baseURI)), data))
241+ ).recover (signature);
242+
243+ if (! OwnableRoles (address (this )).hasAllRoles (signer, Role._MINTER_ROLE)) {
244+ revert SignatureMintUnauthorized ();
245+ }
246+
247+ if (bytes (baseURI).length > 0 ) {
248+ _updateMetadata (to, tokenId, value, baseURI);
249+ }
250+ _beforeMintWithSignature (to, tokenId, value, data);
251+
252+ _totalSupply[tokenId] += value;
253+ _mint (to, tokenId, value, "" );
254+ }
255+
184256 /**
185257 * @notice Burns given amount of tokens.
186258 * @dev Calls the beforeBurn hook. Skips calling the hook if it doesn't exist.
@@ -264,6 +336,19 @@ contract ERC1155CoreInitializable is ERC1155, Core, Multicallable, Initializable
264336 );
265337 }
266338
339+ /// @dev Calls the beforeMintWithSignature hook.
340+ function _beforeMintWithSignature (address to , uint256 tokenId , uint256 value , bytes calldata data )
341+ internal
342+ virtual
343+ {
344+ _executeCallbackFunction (
345+ BeforeMintWithSignatureCallbackERC1155.beforeMintWithSignatureERC1155.selector ,
346+ abi.encodeCall (
347+ BeforeMintWithSignatureCallbackERC1155.beforeMintWithSignatureERC1155, (to, tokenId, value, data)
348+ )
349+ );
350+ }
351+
267352 /// @dev Calls the beforeTransfer hook, if installed.
268353 function _beforeTransfer (address from , address to , uint256 tokenId , uint256 value ) internal virtual {
269354 _executeCallbackFunction (
@@ -307,4 +392,18 @@ contract ERC1155CoreInitializable is ERC1155, Core, Multicallable, Initializable
307392 tokenUri = abi.decode (returndata, (string ));
308393 }
309394
395+ /// @dev Calls the updateMetadata hook, if installed.
396+ function _updateMetadata (address to , uint256 tokenId , uint256 value , string calldata baseURI ) internal virtual {
397+ _executeCallbackFunction (
398+ UpdateMetadataCallbackERC1155.updateMetadataERC1155.selector ,
399+ abi.encodeCall (UpdateMetadataCallbackERC1155.updateMetadataERC1155, (to, tokenId, value, baseURI))
400+ );
401+ }
402+
403+ /// @dev Returns the domain name and version for EIP712.
404+ function _domainNameAndVersion () internal pure override returns (string memory name , string memory version ) {
405+ name = "ERC1155Core " ;
406+ version = "1 " ;
407+ }
408+
310409}
0 commit comments