@zoralabs/protocol-sdk 0.3.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/.turbo/turbo-build.log +6 -6
  2. package/CHANGELOG.md +34 -0
  3. package/README.md +30 -58
  4. package/dist/anvil.d.ts +4 -2
  5. package/dist/anvil.d.ts.map +1 -1
  6. package/dist/constants.d.ts +32 -0
  7. package/dist/constants.d.ts.map +1 -1
  8. package/dist/index.cjs +819 -518
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +788 -493
  13. package/dist/index.js.map +1 -1
  14. package/dist/mint/mint-api-client.d.ts +16 -216
  15. package/dist/mint/mint-api-client.d.ts.map +1 -1
  16. package/dist/mint/mint-client.d.ts +7 -227
  17. package/dist/mint/mint-client.d.ts.map +1 -1
  18. package/dist/premint/contract-types.d.ts +125 -0
  19. package/dist/premint/contract-types.d.ts.map +1 -0
  20. package/dist/premint/premint-api-client.d.ts +14 -7
  21. package/dist/premint/premint-api-client.d.ts.map +1 -1
  22. package/dist/premint/premint-client.d.ts +45 -115
  23. package/dist/premint/premint-client.d.ts.map +1 -1
  24. package/dist/premint/preminter.d.ts +102 -21
  25. package/dist/premint/preminter.d.ts.map +1 -1
  26. package/dist/types.d.ts +2 -0
  27. package/dist/types.d.ts.map +1 -0
  28. package/package.json +1 -1
  29. package/src/anvil.ts +7 -4
  30. package/src/constants.ts +7 -0
  31. package/src/index.ts +2 -0
  32. package/src/mint/mint-api-client.ts +72 -68
  33. package/src/mint/mint-client.test.ts +9 -11
  34. package/src/mint/mint-client.ts +51 -221
  35. package/src/premint/contract-types.ts +109 -0
  36. package/src/premint/premint-api-client.ts +162 -22
  37. package/src/premint/premint-client.test.ts +186 -84
  38. package/src/premint/premint-client.ts +357 -289
  39. package/src/premint/preminter.test.ts +209 -130
  40. package/src/premint/preminter.ts +377 -54
  41. package/src/types.ts +1 -0
  42. package/dist/apis/generated/discover-api-types.d.ts +0 -2131
  43. package/dist/apis/generated/discover-api-types.d.ts.map +0 -1
  44. package/src/apis/generated/discover-api-types.ts +0 -2180
@@ -1,72 +1,395 @@
1
1
  import { Address } from "abitype";
2
- import { ExtractAbiFunction, AbiParametersToPrimitiveTypes } from "abitype";
3
- import { zoraCreator1155PremintExecutorImplABI as preminterAbi } from "@zoralabs/protocol-deployments";
4
- import { TypedDataDefinition } from "viem";
2
+ import {
3
+ zoraCreator1155PremintExecutorImplABI as preminterAbi,
4
+ zoraCreator1155ImplABI,
5
+ zoraCreator1155PremintExecutorImplABI,
6
+ zoraCreator1155PremintExecutorImplAddress,
7
+ } from "@zoralabs/protocol-deployments";
8
+ import {
9
+ TypedDataDefinition,
10
+ recoverTypedDataAddress,
11
+ Hex,
12
+ PublicClient,
13
+ zeroAddress,
14
+ hashDomain,
15
+ keccak256,
16
+ concat,
17
+ recoverAddress,
18
+ GetEventArgs,
19
+ } from "viem";
20
+ import {
21
+ ContractCreationConfig,
22
+ PremintConfig,
23
+ PremintConfigForTokenCreationConfig,
24
+ PremintConfigV1,
25
+ PremintConfigV2,
26
+ PremintConfigVersion,
27
+ PremintConfigWithVersion,
28
+ PreminterDomain,
29
+ TokenCreationConfig,
30
+ v1Types,
31
+ v2Types,
32
+ } from "./contract-types";
5
33
 
6
- type PremintInputs = ExtractAbiFunction<
7
- typeof preminterAbi,
8
- "premint"
9
- >["inputs"];
34
+ export const getPremintExecutorAddress = () =>
35
+ zoraCreator1155PremintExecutorImplAddress[999];
10
36
 
11
- type PreminterHashDataTypes = AbiParametersToPrimitiveTypes<PremintInputs>;
37
+ /**
38
+ * Creates a typed data definition for a premint config. Works for all versions of the premint config by specifying the premintConfigVersion.
39
+ *
40
+ * @param params.verifyingContract the address of the 1155 contract
41
+ * @param params.chainId the chain id the premint is signed for
42
+ * @param params.premintConfigVersion the version of the premint config
43
+ * @param params.premintConfig the premint config
44
+ * @returns
45
+ */
46
+ export const premintTypedDataDefinition = <T extends PremintConfigVersion>({
47
+ verifyingContract,
48
+ chainId,
49
+ premintConfigVersion: version,
50
+ premintConfig,
51
+ }: {
52
+ verifyingContract: Address;
53
+ chainId: number;
54
+ } & PremintConfigWithVersion<T>): TypedDataDefinition => {
55
+ const domain = {
56
+ chainId,
57
+ name: PreminterDomain,
58
+ version,
59
+ verifyingContract: verifyingContract,
60
+ };
12
61
 
13
- export type ContractCreationConfig = PreminterHashDataTypes[0];
14
- export type PremintConfig = PreminterHashDataTypes[1];
15
- export type TokenCreationConfig = PremintConfig["tokenConfig"];
62
+ if (version === PremintConfigVersion.V1)
63
+ return {
64
+ domain,
65
+ types: v1Types,
66
+ message: premintConfig as PremintConfigV1,
67
+ primaryType: "CreatorAttribution",
68
+ } satisfies TypedDataDefinition<typeof v1Types, "CreatorAttribution">;
69
+ if (version === PremintConfigVersion.V2) {
70
+ return {
71
+ domain,
72
+ types: v2Types,
73
+ message: premintConfig as PremintConfigV2,
74
+ primaryType: "CreatorAttribution",
75
+ } satisfies TypedDataDefinition<typeof v2Types, "CreatorAttribution">;
76
+ }
16
77
 
17
- // Convenience method to create the structured typed data
18
- // needed to sign for a premint contract and token
19
- export const preminterTypedDataDefinition = ({
20
- verifyingContract,
78
+ throw new Error(`Invalid version ${version}`);
79
+ };
80
+
81
+ export type IsValidSignatureReturn = {
82
+ isAuthorized: boolean;
83
+ recoveredAddress?: Address;
84
+ };
85
+
86
+ export async function isAuthorizedToCreatePremint<
87
+ T extends PremintConfigVersion,
88
+ >({
89
+ collection,
90
+ collectionAddress,
91
+ publicClient,
21
92
  premintConfig,
22
- chainId,
93
+ premintConfigVersion,
94
+ signature,
95
+ signer,
23
96
  }: {
97
+ collection: ContractCreationConfig;
98
+ collectionAddress: Address;
99
+ publicClient: PublicClient;
100
+ signature: Hex;
101
+ signer: Address;
102
+ } & PremintConfigWithVersion<T>) {
103
+ // if we are using legacy version of premint config, we can use the function
104
+ // "isValidSignature" which we know exists on the premint executor contract
105
+ if (premintConfigVersion === PremintConfigVersion.V1) {
106
+ const [isValidSignature] = await publicClient.readContract({
107
+ abi: zoraCreator1155PremintExecutorImplABI,
108
+ address: getPremintExecutorAddress(),
109
+ functionName: "isValidSignature",
110
+ args: [collection, premintConfig as PremintConfigV1, signature],
111
+ });
112
+
113
+ return isValidSignature;
114
+ }
115
+
116
+ // otherwize, we must assume the newer version of premint executor is deployed, so we call that.
117
+ return await publicClient.readContract({
118
+ abi: preminterAbi,
119
+ address: getPremintExecutorAddress(),
120
+ functionName: "isAuthorizedToCreatePremint",
121
+ args: [signer, collection.contractAdmin, collectionAddress],
122
+ });
123
+ }
124
+
125
+ export async function recoverPremintSigner<T extends PremintConfigVersion>({
126
+ signature,
127
+ ...rest
128
+ }: {
129
+ signature: Hex;
130
+ chainId: number;
24
131
  verifyingContract: Address;
25
- premintConfig: PremintConfig;
132
+ } & PremintConfigWithVersion<T>): Promise<Address> {
133
+ const typedData = premintTypedDataDefinition(rest);
134
+ return await recoverTypedDataAddress({
135
+ ...typedData,
136
+ signature,
137
+ });
138
+ }
139
+
140
+ export async function tryRecoverPremintSigner(
141
+ params: Parameters<typeof recoverPremintSigner>[0],
142
+ ) {
143
+ try {
144
+ return await recoverPremintSigner(params);
145
+ } catch (error) {
146
+ console.error(error);
147
+ return undefined;
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Recovers the address from a typed data signature and then checks if the recovered address is authorized to create a premint
153
+ *
154
+ * @param params validationProperties
155
+ * @param params.typedData typed data definition for premint config
156
+ * @param params.signature signature to validate
157
+ * @param params.publicClient public rpc read-only client
158
+ * @param params.premintConfigContractAdmin the original contractAdmin on the ContractCreationConfig for the premint; this is usually the original creator of the premint
159
+ * @param params.tokenContract the address of the 1155 contract
160
+ * @returns
161
+ */
162
+ export async function isValidSignature<T extends PremintConfigVersion>({
163
+ signature,
164
+ publicClient,
165
+ collection,
166
+ chainId,
167
+ ...premintConfigAndVersion
168
+ }: {
169
+ collection: ContractCreationConfig;
170
+ signature: Hex;
26
171
  chainId: number;
27
- }) => {
28
- const { tokenConfig, uid, version, deleted } = premintConfig;
29
- const types = {
30
- CreatorAttribution: [
31
- { name: "tokenConfig", type: "TokenCreationConfig" },
32
- // unique id scoped to the contract and token to create.
33
- // ensure that a signature can be replaced, as long as the replacement
34
- // has the same uid, and a newer version.
35
- { name: "uid", type: "uint32" },
36
- { name: "version", type: "uint32" },
37
- // if this update should result in the signature being deleted.
38
- { name: "deleted", type: "bool" },
39
- ],
40
- TokenCreationConfig: [
41
- { name: "tokenURI", type: "string" },
42
- { name: "maxSupply", type: "uint256" },
43
- { name: "maxTokensPerAddress", type: "uint64" },
44
- { name: "pricePerToken", type: "uint96" },
45
- { name: "mintStart", type: "uint64" },
46
- { name: "mintDuration", type: "uint64" },
47
- { name: "royaltyMintSchedule", type: "uint32" },
48
- { name: "royaltyBPS", type: "uint32" },
49
- { name: "royaltyRecipient", type: "address" },
50
- { name: "fixedPriceMinter", type: "address" },
51
- ],
172
+ publicClient: PublicClient;
173
+ } & PremintConfigWithVersion<T>): Promise<IsValidSignatureReturn> {
174
+ const tokenContract = await getPremintCollectionAddress({
175
+ collection,
176
+ publicClient,
177
+ });
178
+ const recoveredAddress = await tryRecoverPremintSigner({
179
+ ...premintConfigAndVersion,
180
+ signature,
181
+ verifyingContract: tokenContract,
182
+ chainId,
183
+ });
184
+
185
+ if (!recoverAddress) {
186
+ return {
187
+ isAuthorized: false,
188
+ };
189
+ }
190
+
191
+ const isAuthorized = await isAuthorizedToCreatePremint({
192
+ signer: recoveredAddress!,
193
+ collection,
194
+ collectionAddress: tokenContract,
195
+ publicClient,
196
+ signature,
197
+ ...premintConfigAndVersion,
198
+ });
199
+
200
+ return {
201
+ isAuthorized,
202
+ recoveredAddress,
52
203
  };
204
+ }
53
205
 
54
- const result: TypedDataDefinition<typeof types, "CreatorAttribution"> = {
206
+ /**
207
+ * Converts a premint config from v1 to v2
208
+ *
209
+ * @param premintConfig premint config to convert
210
+ * @param createReferral address that referred the creator, that will receive create referral rewards for the created token
211
+ */
212
+ export function migratePremintConfigToV2({
213
+ premintConfig,
214
+ createReferral = zeroAddress,
215
+ }: {
216
+ premintConfig: PremintConfigV1;
217
+ createReferral: Address;
218
+ }): PremintConfigV2 {
219
+ return {
220
+ ...premintConfig,
221
+ tokenConfig: {
222
+ tokenURI: premintConfig.tokenConfig.tokenURI,
223
+ maxSupply: premintConfig.tokenConfig.maxSupply,
224
+ maxTokensPerAddress: premintConfig.tokenConfig.maxTokensPerAddress,
225
+ pricePerToken: premintConfig.tokenConfig.pricePerToken,
226
+ mintStart: premintConfig.tokenConfig.mintStart,
227
+ mintDuration: premintConfig.tokenConfig.mintDuration,
228
+ payoutRecipient: premintConfig.tokenConfig.royaltyRecipient,
229
+ royaltyBPS: premintConfig.tokenConfig.royaltyBPS,
230
+ fixedPriceMinter: premintConfig.tokenConfig.fixedPriceMinter,
231
+ createReferral,
232
+ },
233
+ };
234
+ }
235
+
236
+ export type CreatorAttributionEventParams = GetEventArgs<
237
+ typeof zoraCreator1155ImplABI,
238
+ "CreatorAttribution",
239
+ { EnableUnion: false }
240
+ >;
241
+
242
+ /**
243
+ * Recovers the address from a CreatorAttribution event emitted from a ZoraCreator1155 contract
244
+ * Useful for verifying that the creator of a token is the one who signed a premint for its creation.
245
+ *
246
+
247
+ * @param creatorAttribution parameters from the CreatorAttribution event
248
+ * @param chainId the chain id of the current chain
249
+ * @param tokenContract the address of the 1155 contract
250
+ * @returns the address of the signer
251
+ */
252
+ export const recoverCreatorFromCreatorAttribution = async ({
253
+ creatorAttribution: { version, domainName, structHash, signature },
254
+ chainId,
255
+ tokenContract,
256
+ }: {
257
+ creatorAttribution: CreatorAttributionEventParams;
258
+ tokenContract: Address;
259
+ chainId: number;
260
+ }) => {
261
+ // hash the eip712 domain based on the parameters emitted from the event:
262
+ const hashedDomain = hashDomain({
55
263
  domain: {
56
264
  chainId,
57
- name: "Preminter",
58
- version: "1",
59
- verifyingContract: verifyingContract,
60
- },
61
- types,
62
- message: {
63
- tokenConfig,
64
- uid,
265
+ name: domainName,
266
+ verifyingContract: tokenContract,
65
267
  version,
66
- deleted,
67
268
  },
68
- primaryType: "CreatorAttribution",
269
+ types: {
270
+ EIP712Domain: [
271
+ { name: "name", type: "string" },
272
+ { name: "version", type: "string" },
273
+ {
274
+ name: "chainId",
275
+ type: "uint256",
276
+ },
277
+ {
278
+ name: "verifyingContract",
279
+ type: "address",
280
+ },
281
+ ],
282
+ },
283
+ });
284
+
285
+ // re-build the eip-712 typed data hash, consisting of the hashed domain and the structHash emitted from the event:
286
+ const parts: Hex[] = ["0x1901", hashedDomain, structHash!];
287
+
288
+ const hashedTypedData = keccak256(concat(parts));
289
+
290
+ return await recoverAddress({
291
+ hash: hashedTypedData,
292
+ signature: signature!,
293
+ });
294
+ };
295
+
296
+ export const supportedPremintVersions = async ({
297
+ tokenContract,
298
+ publicClient,
299
+ }: {
300
+ tokenContract: Address;
301
+ publicClient: PublicClient;
302
+ }): Promise<readonly string[]> => {
303
+ try {
304
+ return await publicClient.readContract({
305
+ abi: preminterAbi,
306
+ address: getPremintExecutorAddress(),
307
+ functionName: "supportedPremintSignatureVersions",
308
+ args: [tokenContract],
309
+ });
310
+ } catch (e) {
311
+ console.error(e);
312
+ // if the premint executor contract doesn't support the function, it must be v1
313
+ return ["1"];
314
+ }
315
+ };
316
+ /**
317
+ * Checks if the 1155 contract at that address supports the given version of the premint config.
318
+ */
319
+ export const supportsPremintVersion = async ({
320
+ version,
321
+ tokenContract,
322
+ publicClient,
323
+ }: {
324
+ version: PremintConfigVersion;
325
+ tokenContract: Address;
326
+ publicClient: PublicClient;
327
+ }): Promise<boolean> => {
328
+ return (
329
+ await supportedPremintVersions({ tokenContract, publicClient })
330
+ ).includes(version);
331
+ };
332
+
333
+ export async function getPremintCollectionAddress({
334
+ collection,
335
+ publicClient,
336
+ }: {
337
+ collection: ContractCreationConfig;
338
+ publicClient: PublicClient;
339
+ }): Promise<Address> {
340
+ return publicClient.readContract({
341
+ address: getPremintExecutorAddress(),
342
+ abi: zoraCreator1155PremintExecutorImplABI,
343
+ functionName: "getContractAddress",
344
+ args: [collection],
345
+ });
346
+ }
347
+
348
+ export function markPremintDeleted<T extends PremintConfig>(
349
+ premintConfig: T,
350
+ ): T {
351
+ return {
352
+ ...premintConfig,
353
+ version: premintConfig.version + 1,
354
+ deleted: true,
69
355
  };
356
+ }
357
+
358
+ export function applyUpdateToPremint({
359
+ uid,
360
+ version,
361
+ tokenConfig,
362
+ tokenConfigUpdates,
363
+ }: {
364
+ tokenConfig: TokenCreationConfig;
365
+ tokenConfigUpdates: Partial<TokenCreationConfig>;
366
+ } & Pick<PremintConfig, "uid" | "version">): PremintConfig {
367
+ const updatedTokenConfig: TokenCreationConfig = {
368
+ ...tokenConfig,
369
+ ...tokenConfigUpdates,
370
+ } as const;
371
+
372
+ const result = {
373
+ deleted: false,
374
+ uid,
375
+ version: version + 1,
376
+ tokenConfig: updatedTokenConfig,
377
+ } as PremintConfig;
70
378
 
71
379
  return result;
72
- };
380
+ }
381
+
382
+ export function makeNewPremint<T extends TokenCreationConfig>({
383
+ tokenConfig,
384
+ uid,
385
+ }: {
386
+ tokenConfig: T;
387
+ uid: number;
388
+ }): PremintConfigForTokenCreationConfig<T> {
389
+ return {
390
+ deleted: false,
391
+ uid,
392
+ version: 0,
393
+ tokenConfig,
394
+ } as PremintConfigForTokenCreationConfig<T>;
395
+ }
package/src/types.ts ADDED
@@ -0,0 +1 @@
1
+ export type GenericTokenIdTypes = number | bigint | string;