@zoralabs/protocol-sdk 0.2.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 (70) hide show
  1. package/.turbo/turbo-build.log +15 -0
  2. package/CHANGELOG.md +47 -0
  3. package/README.md +163 -0
  4. package/dist/anvil.d.ts +16 -0
  5. package/dist/anvil.d.ts.map +1 -0
  6. package/dist/apis/chain-constants.d.ts +21 -0
  7. package/dist/apis/chain-constants.d.ts.map +1 -0
  8. package/dist/apis/client-base.d.ts +15 -0
  9. package/dist/apis/client-base.d.ts.map +1 -0
  10. package/dist/apis/generated/discover-api-types.d.ts +2131 -0
  11. package/dist/apis/generated/discover-api-types.d.ts.map +1 -0
  12. package/dist/apis/generated/premint-api-types.d.ts +356 -0
  13. package/dist/apis/generated/premint-api-types.d.ts.map +1 -0
  14. package/dist/apis/http-api-base.d.ts +26 -0
  15. package/dist/apis/http-api-base.d.ts.map +1 -0
  16. package/dist/constants.d.ts +4 -0
  17. package/dist/constants.d.ts.map +1 -0
  18. package/dist/create/1155-create-helper.d.ts +63 -0
  19. package/dist/create/1155-create-helper.d.ts.map +1 -0
  20. package/dist/create/1155-create-helper.test.d.ts +2 -0
  21. package/dist/create/1155-create-helper.test.d.ts.map +1 -0
  22. package/dist/index.cjs +1006 -0
  23. package/dist/index.cjs.map +1 -0
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +984 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/mint/mint-api-client.d.ts +20 -0
  29. package/dist/mint/mint-api-client.d.ts.map +1 -0
  30. package/dist/mint/mint-client.d.ts +237 -0
  31. package/dist/mint/mint-client.d.ts.map +1 -0
  32. package/dist/mint/mint-client.test.d.ts +2 -0
  33. package/dist/mint/mint-client.test.d.ts.map +1 -0
  34. package/dist/premint/premint-api-client.d.ts +19 -0
  35. package/dist/premint/premint-api-client.d.ts.map +1 -0
  36. package/dist/premint/premint-client.d.ts +320 -0
  37. package/dist/premint/premint-client.d.ts.map +1 -0
  38. package/dist/premint/premint-client.test.d.ts +2 -0
  39. package/dist/premint/premint-client.test.d.ts.map +1 -0
  40. package/dist/premint/preminter.d.ts +25 -0
  41. package/dist/premint/preminter.d.ts.map +1 -0
  42. package/dist/premint/preminter.test.d.ts +2 -0
  43. package/dist/premint/preminter.test.d.ts.map +1 -0
  44. package/dist/preminter.d.ts +25 -0
  45. package/dist/preminter.d.ts.map +1 -0
  46. package/dist/preminter.test.d.ts +451 -0
  47. package/dist/preminter.test.d.ts.map +1 -0
  48. package/package.json +28 -0
  49. package/src/anvil.ts +84 -0
  50. package/src/apis/chain-constants.ts +101 -0
  51. package/src/apis/client-base.ts +29 -0
  52. package/src/apis/generated/discover-api-types.ts +2138 -0
  53. package/src/apis/generated/premint-api-types.ts +363 -0
  54. package/src/apis/http-api-base.ts +93 -0
  55. package/src/constants.ts +10 -0
  56. package/src/create/1155-create-helper.test.ts +90 -0
  57. package/src/create/1155-create-helper.ts +342 -0
  58. package/src/index.ts +9 -0
  59. package/src/mint/mint-api-client.ts +52 -0
  60. package/src/mint/mint-client.test.ts +117 -0
  61. package/src/mint/mint-client.ts +218 -0
  62. package/src/premint/premint-api-client.ts +57 -0
  63. package/src/premint/premint-client.test.ts +196 -0
  64. package/src/premint/premint-client.ts +619 -0
  65. package/src/premint/preminter.test.ts +502 -0
  66. package/src/premint/preminter.ts +72 -0
  67. package/src/preminter.test.ts +510 -0
  68. package/src/preminter.ts +72 -0
  69. package/tsconfig.json +25 -0
  70. package/tsup.config.js +10 -0
@@ -0,0 +1,502 @@
1
+ import { keccak256, Hex, concat, recoverAddress, hashDomain, Address } from "viem";
2
+ import { foundry } from "viem/chains";
3
+ import { describe, expect } from "vitest";
4
+ import { parseEther } from "viem";
5
+ import {
6
+ zoraCreator1155PremintExecutorImplABI as preminterAbi,
7
+ zoraCreator1155PremintExecutorImplAddress as zoraCreator1155PremintExecutorAddress,
8
+ zoraCreator1155ImplABI,
9
+ zoraCreator1155FactoryImplAddress,
10
+ zoraCreator1155FactoryImplConfig,
11
+ } from "@zoralabs/protocol-deployments";
12
+
13
+ import {
14
+ ContractCreationConfig,
15
+ PremintConfig,
16
+ TokenCreationConfig,
17
+ preminterTypedDataDefinition,
18
+ } from "./preminter";
19
+ import { AnvilViemClientsTest, anvilTest } from "src/anvil";
20
+
21
+ // create token and contract creation config:
22
+ const defaultContractConfig = ({
23
+ contractAdmin,
24
+ }: {
25
+ contractAdmin: Address;
26
+ }): ContractCreationConfig => ({
27
+ contractAdmin,
28
+ contractURI: "ipfs://asdfasdfasdf",
29
+ contractName: "My fun NFT",
30
+ });
31
+
32
+ const defaultTokenConfig = (
33
+ fixedPriceMinterAddress: Address,
34
+ creatorAccount: Address,
35
+ ): TokenCreationConfig => ({
36
+ tokenURI: "ipfs://tokenIpfsId0",
37
+ maxSupply: 100n,
38
+ maxTokensPerAddress: 10n,
39
+ pricePerToken: 0n,
40
+ mintStart: 0n,
41
+ mintDuration: 100n,
42
+ royaltyMintSchedule: 30,
43
+ royaltyBPS: 200,
44
+ royaltyRecipient: creatorAccount,
45
+ fixedPriceMinter: fixedPriceMinterAddress,
46
+ });
47
+
48
+ const defaultPremintConfig = (
49
+ fixedPriceMinter: Address,
50
+ creatorAccount: Address,
51
+ ): PremintConfig => ({
52
+ tokenConfig: defaultTokenConfig(fixedPriceMinter, creatorAccount),
53
+ deleted: false,
54
+ uid: 105,
55
+ version: 0,
56
+ });
57
+
58
+ const ZORA_MINT_FEE = parseEther("0.000777");
59
+
60
+ const PREMINTER_ADDRESS = zoraCreator1155PremintExecutorAddress[999];
61
+
62
+ async function setupContracts({
63
+ viemClients: { walletClient, testClient, publicClient },
64
+ }: AnvilViemClientsTest) {
65
+ // JSON-RPC Account
66
+ const [deployerAccount, creatorAccount, collectorAccount] =
67
+ (await walletClient.getAddresses()) as [Address, Address, Address, Address];
68
+
69
+ // deploy signature minter contract
70
+ await testClient.setBalance({
71
+ address: deployerAccount,
72
+ value: parseEther("10"),
73
+ });
74
+
75
+ const fixedPriceMinterAddress = await publicClient.readContract({
76
+ abi: zoraCreator1155FactoryImplConfig.abi,
77
+ address: zoraCreator1155FactoryImplAddress[999],
78
+ functionName: "fixedPriceMinter",
79
+ });
80
+
81
+ return {
82
+ accounts: {
83
+ deployerAccount,
84
+ creatorAccount,
85
+ collectorAccount,
86
+ },
87
+ fixedPriceMinterAddress,
88
+ };
89
+ }
90
+
91
+ describe("ZoraCreator1155Preminter", () => {
92
+ // skip for now - we need to make this work on zora testnet chain too
93
+ anvilTest(
94
+ "can sign on the forked premint contract",
95
+ async ({ viemClients }) => {
96
+ const {
97
+ fixedPriceMinterAddress,
98
+ accounts: { creatorAccount },
99
+ } = await setupContracts({ viemClients });
100
+ const premintConfig = defaultPremintConfig(
101
+ fixedPriceMinterAddress,
102
+ creatorAccount,
103
+ );
104
+ const contractConfig = defaultContractConfig({
105
+ contractAdmin: creatorAccount,
106
+ });
107
+
108
+ const preminterAddress = zoraCreator1155PremintExecutorAddress[999];
109
+
110
+ const contractAddress = await viemClients.publicClient.readContract({
111
+ abi: preminterAbi,
112
+ address: preminterAddress,
113
+ functionName: "getContractAddress",
114
+ args: [contractConfig],
115
+ });
116
+
117
+ const signedMessage = await viemClients.walletClient.signTypedData({
118
+ ...preminterTypedDataDefinition({
119
+ verifyingContract: contractAddress,
120
+ chainId: 999,
121
+ premintConfig,
122
+ }),
123
+ account: creatorAccount,
124
+ });
125
+
126
+ console.log({
127
+ creatorAccount,
128
+ signedMessage,
129
+ contractConfig,
130
+ premintConfig,
131
+ contractAddress,
132
+ });
133
+ },
134
+ 20 * 1000,
135
+ );
136
+ anvilTest(
137
+ "can sign and recover a signature",
138
+ async ({ viemClients }) => {
139
+ const {
140
+ fixedPriceMinterAddress,
141
+ accounts: { creatorAccount },
142
+ } = await setupContracts({ viemClients });
143
+
144
+ const premintConfig = defaultPremintConfig(
145
+ fixedPriceMinterAddress,
146
+ creatorAccount,
147
+ );
148
+ const contractConfig = defaultContractConfig({
149
+ contractAdmin: creatorAccount,
150
+ });
151
+
152
+ const contractAddress = await viemClients.publicClient.readContract({
153
+ abi: preminterAbi,
154
+ address: PREMINTER_ADDRESS,
155
+ functionName: "getContractAddress",
156
+ args: [contractConfig],
157
+ });
158
+
159
+ // sign message containing contract and token creation config and uid
160
+ const signedMessage = await viemClients.walletClient.signTypedData({
161
+ ...preminterTypedDataDefinition({
162
+ verifyingContract: contractAddress,
163
+ // we need to sign here for the anvil chain, cause thats where it is run on
164
+ chainId: foundry.id,
165
+ premintConfig,
166
+ }),
167
+ account: creatorAccount,
168
+ });
169
+
170
+ // recover and verify address is correct
171
+ const recoveredAddress = await viemClients.publicClient.readContract({
172
+ abi: preminterAbi,
173
+ address: PREMINTER_ADDRESS,
174
+ functionName: "recoverSigner",
175
+ args: [premintConfig, contractAddress, signedMessage],
176
+ });
177
+
178
+ expect(recoveredAddress).to.equal(creatorAccount);
179
+ },
180
+
181
+ 20 * 1000,
182
+ );
183
+ anvilTest(
184
+ "can sign and mint multiple tokens",
185
+ async ({ viemClients }) => {
186
+ const {
187
+ fixedPriceMinterAddress,
188
+ accounts: { creatorAccount, collectorAccount },
189
+ } = await setupContracts({ viemClients });
190
+ // setup contract and token creation parameters
191
+ const premintConfig = defaultPremintConfig(
192
+ fixedPriceMinterAddress,
193
+ creatorAccount,
194
+ );
195
+ const contractConfig = defaultContractConfig({
196
+ contractAdmin: creatorAccount,
197
+ });
198
+
199
+ // lets make it a random number to not break the existing tests that expect fresh data
200
+ premintConfig.uid = Math.round(Math.random() * 1000000);
201
+
202
+ let contractAddress = await viemClients.publicClient.readContract({
203
+ abi: preminterAbi,
204
+ address: PREMINTER_ADDRESS,
205
+ functionName: "getContractAddress",
206
+ args: [contractConfig],
207
+ });
208
+
209
+ // have creator sign the message to create the contract
210
+ // and the token
211
+ const signedMessage = await viemClients.walletClient.signTypedData({
212
+ ...preminterTypedDataDefinition({
213
+ verifyingContract: contractAddress,
214
+ // we need to sign here for the anvil chain, cause thats where it is run on
215
+ chainId: foundry.id,
216
+ premintConfig,
217
+ }),
218
+ account: creatorAccount,
219
+ });
220
+
221
+ const quantityToMint = 2n;
222
+
223
+ const valueToSend =
224
+ (ZORA_MINT_FEE + premintConfig.tokenConfig.pricePerToken) *
225
+ quantityToMint;
226
+
227
+ const comment = "I love this!";
228
+
229
+ await viemClients.testClient.setBalance({
230
+ address: collectorAccount,
231
+ value: parseEther("10"),
232
+ });
233
+
234
+ // get the premint status - it should not be minted
235
+ let [contractCreated, tokenId] =
236
+ await viemClients.publicClient.readContract({
237
+ abi: preminterAbi,
238
+ address: PREMINTER_ADDRESS,
239
+ functionName: "premintStatus",
240
+ args: [contractAddress, premintConfig.uid],
241
+ });
242
+
243
+ expect(contractCreated).toBe(false);
244
+ expect(tokenId).toBe(0n);
245
+
246
+ // now have the collector execute the first signed message;
247
+ // it should create the contract, the token,
248
+ // and min the quantity to mint tokens to the collector
249
+ // the signature along with contract + token creation
250
+ // parameters are required to call this function
251
+ const mintHash = await viemClients.walletClient.writeContract({
252
+ abi: preminterAbi,
253
+ functionName: "premint",
254
+ account: collectorAccount,
255
+ chain: foundry,
256
+ address: PREMINTER_ADDRESS,
257
+ args: [
258
+ contractConfig,
259
+ premintConfig,
260
+ signedMessage,
261
+ quantityToMint,
262
+ comment,
263
+ ],
264
+ value: valueToSend,
265
+ });
266
+
267
+ // ensure it succeeded
268
+ const receipt = await viemClients.publicClient.waitForTransactionReceipt({
269
+ hash: mintHash,
270
+ });
271
+
272
+ expect(receipt.status).toBe("success");
273
+
274
+ // fetch the premint token id
275
+ [contractCreated, tokenId] = await viemClients.publicClient.readContract({
276
+ abi: preminterAbi,
277
+ address: PREMINTER_ADDRESS,
278
+ functionName: "premintStatus",
279
+ args: [contractAddress, premintConfig.uid],
280
+ });
281
+
282
+ expect(tokenId).not.toBe(0n);
283
+
284
+ // now use what was created, to get the balance from the created contract
285
+ const tokenBalance = await viemClients.publicClient.readContract({
286
+ abi: zoraCreator1155ImplABI,
287
+ address: contractAddress,
288
+ functionName: "balanceOf",
289
+ args: [collectorAccount, tokenId],
290
+ });
291
+
292
+ // get token balance - should be amount that was created
293
+ expect(tokenBalance).toBe(quantityToMint);
294
+
295
+ const premintConfig2 = {
296
+ ...premintConfig,
297
+ uid: premintConfig.uid + 1,
298
+ tokenConfig: {
299
+ ...premintConfig.tokenConfig,
300
+ tokenURI: "ipfs://tokenIpfsId2",
301
+ pricePerToken: parseEther("0.05"),
302
+ },
303
+ };
304
+
305
+ // sign the message to create the second token
306
+ const signedMessage2 = await viemClients.walletClient.signTypedData({
307
+ ...preminterTypedDataDefinition({
308
+ verifyingContract: contractAddress,
309
+ chainId: foundry.id,
310
+ premintConfig: premintConfig2,
311
+ }),
312
+ account: creatorAccount,
313
+ });
314
+
315
+ const quantityToMint2 = 4n;
316
+
317
+ const valueToSend2 =
318
+ (ZORA_MINT_FEE + premintConfig2.tokenConfig.pricePerToken) *
319
+ quantityToMint2;
320
+
321
+ // now have the collector execute the second signed message.
322
+ // it should create a new token against the existing contract
323
+ const mintHash2 = await viemClients.walletClient.writeContract({
324
+ abi: preminterAbi,
325
+ functionName: "premint",
326
+ account: collectorAccount,
327
+ chain: foundry,
328
+ address: PREMINTER_ADDRESS,
329
+ args: [
330
+ contractConfig,
331
+ premintConfig2,
332
+ signedMessage2,
333
+ quantityToMint2,
334
+ comment,
335
+ ],
336
+ value: valueToSend2,
337
+ });
338
+
339
+ expect(
340
+ (
341
+ await viemClients.publicClient.waitForTransactionReceipt({
342
+ hash: mintHash2,
343
+ })
344
+ ).status,
345
+ ).toBe("success");
346
+
347
+ // now premint status for the second mint, it should be minted
348
+ [, tokenId] = await viemClients.publicClient.readContract({
349
+ abi: preminterAbi,
350
+ address: PREMINTER_ADDRESS,
351
+ functionName: "premintStatus",
352
+ args: [contractAddress, premintConfig2.uid],
353
+ });
354
+
355
+ expect(tokenId).not.toBe(0n);
356
+
357
+ // get balance of second token
358
+ const tokenBalance2 = await viemClients.publicClient.readContract({
359
+ abi: zoraCreator1155ImplABI,
360
+ address: contractAddress,
361
+ functionName: "balanceOf",
362
+ args: [collectorAccount, tokenId],
363
+ });
364
+
365
+ expect(tokenBalance2).toBe(quantityToMint2);
366
+ },
367
+ // 10 second timeout
368
+ 40 * 1000,
369
+ );
370
+
371
+ anvilTest(
372
+ "can decode the CreatorAttribution event",
373
+ async ({ viemClients }) => {
374
+ const {
375
+ fixedPriceMinterAddress,
376
+ accounts: { creatorAccount, collectorAccount },
377
+ } = await setupContracts({ viemClients });
378
+ const premintConfig = defaultPremintConfig(
379
+ fixedPriceMinterAddress,
380
+ creatorAccount,
381
+ );
382
+ const contractConfig = defaultContractConfig({
383
+ contractAdmin: creatorAccount,
384
+ });
385
+
386
+ // lets make it a random number to not break the existing tests that expect fresh data
387
+ premintConfig.uid = Math.round(Math.random() * 1000000);
388
+
389
+ let contractAddress = await viemClients.publicClient.readContract({
390
+ abi: preminterAbi,
391
+ address: PREMINTER_ADDRESS,
392
+ functionName: "getContractAddress",
393
+ args: [contractConfig],
394
+ });
395
+
396
+ // have creator sign the message to create the contract
397
+ // and the token
398
+ const signedMessage = await viemClients.walletClient.signTypedData({
399
+ ...preminterTypedDataDefinition({
400
+ verifyingContract: contractAddress,
401
+ // we need to sign here for the anvil chain, cause thats where it is run on
402
+ chainId: foundry.id,
403
+ premintConfig,
404
+ }),
405
+ account: creatorAccount,
406
+ });
407
+
408
+ const quantityToMint = 2n;
409
+
410
+ const valueToSend =
411
+ (ZORA_MINT_FEE + premintConfig.tokenConfig.pricePerToken) *
412
+ quantityToMint;
413
+
414
+ const comment = "I love this!";
415
+
416
+ await viemClients.testClient.setBalance({
417
+ address: collectorAccount,
418
+ value: parseEther("10"),
419
+ });
420
+
421
+ // now have the collector execute the first signed message;
422
+ // it should create the contract, the token,
423
+ // and min the quantity to mint tokens to the collector
424
+ // the signature along with contract + token creation
425
+ // parameters are required to call this function
426
+ const mintHash = await viemClients.walletClient.writeContract({
427
+ abi: preminterAbi,
428
+ functionName: "premint",
429
+ account: collectorAccount,
430
+ chain: foundry,
431
+ address: PREMINTER_ADDRESS,
432
+ args: [
433
+ contractConfig,
434
+ premintConfig,
435
+ signedMessage,
436
+ quantityToMint,
437
+ comment,
438
+ ],
439
+ value: valueToSend,
440
+ });
441
+
442
+ // ensure it succeeded
443
+ const receipt = await viemClients.publicClient.waitForTransactionReceipt({
444
+ hash: mintHash,
445
+ });
446
+
447
+ expect(receipt.status).toBe("success");
448
+
449
+ // get the CreatorAttribution event from the erc1155 contract:
450
+ const topics = await viemClients.publicClient.getContractEvents({
451
+ abi: zoraCreator1155ImplABI,
452
+ address: contractAddress,
453
+ eventName: "CreatorAttribution",
454
+ });
455
+
456
+ expect(topics.length).toBe(1);
457
+
458
+ const creatorAttributionEvent = topics[0]!;
459
+
460
+ const { creator, domainName, signature, structHash, version } =
461
+ creatorAttributionEvent.args;
462
+
463
+ const chainId = foundry.id;
464
+
465
+ // hash the eip712 domain based on the parameters emitted from the event:
466
+ const hashedDomain = hashDomain({
467
+ domain: {
468
+ chainId,
469
+ name: domainName,
470
+ verifyingContract: contractAddress,
471
+ version,
472
+ },
473
+ types: {
474
+ EIP712Domain: [
475
+ { name: "name", type: "string" },
476
+ { name: "version", type: "string" },
477
+ {
478
+ name: "chainId",
479
+ type: "uint256",
480
+ },
481
+ {
482
+ name: "verifyingContract",
483
+ type: "address",
484
+ },
485
+ ],
486
+ },
487
+ });
488
+
489
+ // re-build the eip-712 typed data hash, consisting of the hashed domain and the structHash emitted from the event:
490
+ const parts: Hex[] = ["0x1901", hashedDomain, structHash!];
491
+
492
+ const hashedTypedData = keccak256(concat(parts));
493
+
494
+ const recoveredSigner = await recoverAddress({
495
+ hash: hashedTypedData,
496
+ signature: signature!,
497
+ });
498
+
499
+ expect(recoveredSigner).toBe(creator);
500
+ },
501
+ );
502
+ });
@@ -0,0 +1,72 @@
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";
5
+
6
+ type PremintInputs = ExtractAbiFunction<
7
+ typeof preminterAbi,
8
+ "premint"
9
+ >["inputs"];
10
+
11
+ type PreminterHashDataTypes = AbiParametersToPrimitiveTypes<PremintInputs>;
12
+
13
+ export type ContractCreationConfig = PreminterHashDataTypes[0];
14
+ export type PremintConfig = PreminterHashDataTypes[1];
15
+ export type TokenCreationConfig = PremintConfig["tokenConfig"];
16
+
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,
21
+ premintConfig,
22
+ chainId,
23
+ }: {
24
+ verifyingContract: Address;
25
+ premintConfig: PremintConfig;
26
+ 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
+ ],
52
+ };
53
+
54
+ const result: TypedDataDefinition<typeof types, "CreatorAttribution"> = {
55
+ domain: {
56
+ chainId,
57
+ name: "Preminter",
58
+ version: "1",
59
+ verifyingContract: verifyingContract,
60
+ },
61
+ types,
62
+ message: {
63
+ tokenConfig,
64
+ uid,
65
+ version,
66
+ deleted,
67
+ },
68
+ primaryType: "CreatorAttribution",
69
+ };
70
+
71
+ return result;
72
+ };