@zoralabs/protocol-sdk 0.5.8-DEV.2 → 0.5.8

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.
@@ -0,0 +1,719 @@
1
+ import { describe, expect } from "vitest";
2
+
3
+ import { forkUrls, makeAnvilTest } from "src/anvil";
4
+ import {
5
+ defaultContractConfig,
6
+ defaultPremintConfigV2,
7
+ } from "src/premint/preminter.test";
8
+ import {
9
+ mintsEthUnwrapperAndCallerConfig,
10
+ zoraCreator1155FactoryImplAddress,
11
+ zoraCreator1155FactoryImplConfig,
12
+ zoraCreator1155ImplABI,
13
+ zoraMints1155ABI,
14
+ zoraMints1155Address,
15
+ zoraMintsManagerImplABI,
16
+ zoraMintsManagerImplAddress,
17
+ } from "@zoralabs/protocol-deployments";
18
+ import {
19
+ Address,
20
+ BaseError,
21
+ ContractFunctionRevertedError,
22
+ Hex,
23
+ PublicClient,
24
+ WalletClient,
25
+ encodeFunctionData,
26
+ parseEther,
27
+ } from "viem";
28
+ import {
29
+ collectPremintV2WithMintsParams,
30
+ collectWithMintsParams,
31
+ mintWithEthParams,
32
+ permitTransferBatchToManagerAndCallParams,
33
+ mintsBalanceOfAccountParams,
34
+ collectPremintWithMintsTypedDataDefinition,
35
+ CollectMintArguments,
36
+ fixedPriceMinterMinterArguments,
37
+ decodeCallFailedError,
38
+ safeTransferBatchAndUnwrapTypedDataDefinition,
39
+ safeTransferAndUnwrapTypedDataDefinition,
40
+ } from "./mints-contracts";
41
+ import { getPremintCollectionAddress } from "src/premint/preminter";
42
+ import {
43
+ MintArguments as PremintMintArguments,
44
+ PremintConfigVersion,
45
+ } from "src/premint/contract-types";
46
+ import { premintTypedDataDefinition } from "src/premint/preminter";
47
+ import { zoraSepolia } from "viem/chains";
48
+
49
+ const anvilTest = makeAnvilTest({
50
+ forkUrl: forkUrls.zoraSepolia,
51
+ forkBlockNumber: 7137785,
52
+ anvilChainId: zoraSepolia.id,
53
+ });
54
+
55
+ const getFixedPricedMinter = async ({
56
+ publicClient,
57
+ chainId,
58
+ }: {
59
+ publicClient: PublicClient;
60
+ chainId: keyof typeof zoraCreator1155FactoryImplAddress;
61
+ }) =>
62
+ await publicClient.readContract({
63
+ abi: zoraCreator1155FactoryImplConfig.abi,
64
+ address: zoraCreator1155FactoryImplAddress[chainId],
65
+ functionName: "fixedPriceMinter",
66
+ });
67
+
68
+ const setupContractUsingPremint = async ({
69
+ walletClient,
70
+ publicClient,
71
+ chainId,
72
+ creatorAccount,
73
+ }: {
74
+ walletClient: WalletClient;
75
+ publicClient: PublicClient;
76
+ chainId: keyof typeof zoraMintsManagerImplAddress;
77
+ creatorAccount: Address;
78
+ }) => {
79
+ const fixedPriceMinter = await getFixedPricedMinter({
80
+ publicClient,
81
+ chainId,
82
+ });
83
+
84
+ const premintConfig = defaultPremintConfigV2({
85
+ fixedPriceMinter,
86
+ creatorAccount: creatorAccount!,
87
+ pricePerToken: 0n,
88
+ });
89
+
90
+ const contractConfig = defaultContractConfig({
91
+ contractAdmin: creatorAccount!,
92
+ });
93
+
94
+ contractConfig.contractName = "Testing contract for MINTS";
95
+
96
+ const contractAddress = await getPremintCollectionAddress({
97
+ collection: contractConfig,
98
+ publicClient,
99
+ });
100
+
101
+ const signature = await walletClient.signTypedData({
102
+ ...premintTypedDataDefinition({
103
+ verifyingContract: contractAddress,
104
+ chainId,
105
+ premintConfig,
106
+ premintConfigVersion: PremintConfigVersion.V2,
107
+ }),
108
+ account: creatorAccount!,
109
+ });
110
+
111
+ return {
112
+ premintConfig,
113
+ contractConfig,
114
+ contractAddress,
115
+ signature,
116
+ fixedPriceMinter,
117
+ };
118
+ };
119
+
120
+ const waitForSuccess = async (hash: Hex, publicClient: PublicClient) => {
121
+ const receipt = await publicClient.waitForTransactionReceipt({
122
+ hash,
123
+ });
124
+
125
+ expect(receipt.status).toBe("success");
126
+ };
127
+
128
+ const collectMINTsWithEth = async ({
129
+ publicClient,
130
+ walletClient,
131
+ chainId,
132
+ collectorAccount,
133
+ quantityToMint,
134
+ }: {
135
+ publicClient: PublicClient;
136
+ chainId: keyof typeof zoraMintsManagerImplAddress;
137
+ collectorAccount: Address;
138
+ quantityToMint: bigint;
139
+ walletClient: WalletClient;
140
+ }) => {
141
+ const pricePerMint = await publicClient.readContract({
142
+ abi: zoraMintsManagerImplABI,
143
+ address: zoraMintsManagerImplAddress[chainId],
144
+ functionName: "getEthPrice",
145
+ });
146
+
147
+ const simulated = await publicClient.simulateContract(
148
+ mintWithEthParams({
149
+ chainId: chainId,
150
+ quantity: quantityToMint,
151
+ recipient: collectorAccount!,
152
+ pricePerMint,
153
+ account: collectorAccount!,
154
+ }),
155
+ );
156
+
157
+ await waitForSuccess(
158
+ await walletClient.writeContract(simulated.request),
159
+ publicClient,
160
+ );
161
+ const mintsTokenId = await publicClient.readContract({
162
+ abi: zoraMintsManagerImplABI,
163
+ address: zoraMintsManagerImplAddress[chainId],
164
+ functionName: "mintableEthToken",
165
+ });
166
+
167
+ return mintsTokenId;
168
+ };
169
+
170
+ describe("MINTs collecting and redeeming.", () => {
171
+ anvilTest(
172
+ "can collect MINTs with ETH",
173
+ async ({
174
+ viemClients: { testClient, walletClient, publicClient, chain },
175
+ }) => {
176
+ const [collectorAccount] = await walletClient.getAddresses();
177
+ const initialMintsQuantityToMint = 20n;
178
+
179
+ await testClient.setBalance({
180
+ address: collectorAccount!,
181
+ value: parseEther("10"),
182
+ });
183
+
184
+ const chainId = chain.id as keyof typeof zoraMintsManagerImplAddress;
185
+
186
+ const pricePerMint = await publicClient.readContract({
187
+ abi: zoraMintsManagerImplABI,
188
+ address: zoraMintsManagerImplAddress[chainId],
189
+ functionName: "getEthPrice",
190
+ });
191
+
192
+ const simulated = await publicClient.simulateContract(
193
+ mintWithEthParams({
194
+ chainId: chainId,
195
+ quantity: initialMintsQuantityToMint,
196
+ recipient: collectorAccount!,
197
+ pricePerMint,
198
+ account: collectorAccount!,
199
+ }),
200
+ );
201
+
202
+ await waitForSuccess(
203
+ await walletClient.writeContract(simulated.request),
204
+ publicClient,
205
+ );
206
+
207
+ // check that the balance is correct
208
+ const totalMintsBalance = await publicClient.readContract(
209
+ mintsBalanceOfAccountParams({
210
+ account: collectorAccount!,
211
+ chainId: chainId,
212
+ }),
213
+ );
214
+
215
+ expect(totalMintsBalance).toEqual(initialMintsQuantityToMint);
216
+ },
217
+ );
218
+ anvilTest(
219
+ "can use MINTSs to collect premint and non-premint",
220
+ async ({
221
+ viemClients: { walletClient, publicClient, testClient, chain },
222
+ }) => {
223
+ const [collectorAccount, creatorAccount] =
224
+ await walletClient.getAddresses();
225
+
226
+ const chainId = chain.id as keyof typeof zoraMintsManagerImplAddress;
227
+
228
+ // 1. Create a premint and contract creation config
229
+ const {
230
+ premintConfig,
231
+ contractConfig,
232
+ contractAddress,
233
+ signature: premintSignature,
234
+ fixedPriceMinter,
235
+ } = await setupContractUsingPremint({
236
+ walletClient,
237
+ publicClient,
238
+ chainId,
239
+ creatorAccount: creatorAccount!,
240
+ });
241
+
242
+ await testClient.setBalance({
243
+ address: collectorAccount!,
244
+ value: parseEther("10"),
245
+ });
246
+
247
+ const initialMINTsBalance = await publicClient.readContract(
248
+ mintsBalanceOfAccountParams({
249
+ account: collectorAccount!,
250
+ chainId: chainId,
251
+ }),
252
+ );
253
+
254
+ // 2. Collect some MINTs
255
+ const initialMintsQuantityToMint = 20n;
256
+
257
+ const mintsTokenId = await collectMINTsWithEth({
258
+ publicClient,
259
+ walletClient,
260
+ chainId,
261
+ collectorAccount: collectorAccount!,
262
+ quantityToMint: initialMintsQuantityToMint,
263
+ });
264
+
265
+ expect(
266
+ await publicClient.readContract(
267
+ mintsBalanceOfAccountParams({
268
+ account: collectorAccount!,
269
+ chainId: chainId,
270
+ }),
271
+ ),
272
+ ).toEqual(initialMINTsBalance + initialMintsQuantityToMint);
273
+
274
+ // 3. Use MINTS to collect the premint
275
+ const mintArguments: PremintMintArguments = {
276
+ mintComment: "Hi!",
277
+ mintRecipient: collectorAccount!,
278
+ mintRewardsRecipients: [],
279
+ };
280
+
281
+ const firstQuantityToCollect = 4n;
282
+
283
+ // 4. Collect Premint using MINT
284
+
285
+ const collectPremintSimulated = await publicClient.simulateContract(
286
+ collectPremintV2WithMintsParams({
287
+ tokenIds: [mintsTokenId],
288
+ quantities: [firstQuantityToCollect],
289
+ chainId: chainId,
290
+ contractCreationConfig: contractConfig,
291
+ premintConfig: premintConfig,
292
+ mintArguments,
293
+ premintSignature: premintSignature,
294
+ account: collectorAccount!,
295
+ }),
296
+ );
297
+
298
+ await waitForSuccess(
299
+ await walletClient.writeContract(collectPremintSimulated.request),
300
+ publicClient,
301
+ );
302
+
303
+ const erc1155Balance = await publicClient.readContract({
304
+ abi: zoraCreator1155ImplABI,
305
+ address: contractAddress,
306
+ functionName: "balanceOf",
307
+ args: [collectorAccount!, mintsTokenId],
308
+ });
309
+
310
+ expect(erc1155Balance).toBe(firstQuantityToCollect);
311
+
312
+ // 4. Use MINTs to collect from the created contract non-premint.
313
+ const secondQuantityToCollect = 3n;
314
+
315
+ const collectMintArguments: CollectMintArguments = {
316
+ mintComment: "comment!",
317
+ minterArguments: fixedPriceMinterMinterArguments({
318
+ mintRecipient: collectorAccount!,
319
+ }),
320
+ mintRewardsRecipients: [],
321
+ };
322
+
323
+ const collectSimulated = await publicClient.simulateContract(
324
+ collectWithMintsParams({
325
+ tokenIds: [mintsTokenId],
326
+ quantities: [secondQuantityToCollect],
327
+ account: collectorAccount!,
328
+ chainId: chainId,
329
+ minter: fixedPriceMinter,
330
+ mintArguments: collectMintArguments,
331
+ zoraCreator1155Contract: contractAddress,
332
+ zoraCreator1155TokenId: 1n,
333
+ }),
334
+ );
335
+
336
+ await waitForSuccess(
337
+ await walletClient.writeContract(collectSimulated.request),
338
+ publicClient,
339
+ );
340
+
341
+ const erc1155BalanceAfter = await publicClient.readContract({
342
+ abi: zoraCreator1155ImplABI,
343
+ address: contractAddress,
344
+ functionName: "balanceOf",
345
+ args: [collectorAccount!, mintsTokenId],
346
+ });
347
+
348
+ expect(erc1155BalanceAfter).toBe(
349
+ firstQuantityToCollect + secondQuantityToCollect,
350
+ );
351
+
352
+ const totalMintsBalance = await publicClient.readContract(
353
+ mintsBalanceOfAccountParams({
354
+ account: collectorAccount!,
355
+ chainId: chainId,
356
+ }),
357
+ );
358
+
359
+ expect(totalMintsBalance).toBe(
360
+ initialMINTsBalance +
361
+ initialMintsQuantityToMint -
362
+ (firstQuantityToCollect + secondQuantityToCollect),
363
+ );
364
+ },
365
+ );
366
+ anvilTest(
367
+ "can decode errors from transferBatchToManagerAndCall",
368
+ async ({
369
+ viemClients: { walletClient, publicClient, testClient, chain },
370
+ }) => {
371
+ const [collectorAccount, creatorAccount] =
372
+ await walletClient.getAddresses();
373
+
374
+ const chainId = chain.id as keyof typeof zoraMintsManagerImplAddress;
375
+
376
+ // 1. Create a premint and contract creation config
377
+ const { premintConfig, contractConfig } = await setupContractUsingPremint(
378
+ {
379
+ walletClient,
380
+ publicClient,
381
+ chainId,
382
+ creatorAccount: creatorAccount!,
383
+ },
384
+ );
385
+
386
+ await testClient.setBalance({
387
+ address: collectorAccount!,
388
+ value: parseEther("10"),
389
+ });
390
+
391
+ // 2. Collect some MINTs
392
+ const mintsTokenId = await collectMINTsWithEth({
393
+ publicClient,
394
+ walletClient,
395
+ chainId,
396
+ collectorAccount: collectorAccount!,
397
+ quantityToMint: 10n,
398
+ });
399
+
400
+ // 3. Use MINTS to collect the premint
401
+ const mintArguments: PremintMintArguments = {
402
+ mintComment: "",
403
+ mintRecipient: collectorAccount!,
404
+ mintRewardsRecipients: [],
405
+ };
406
+
407
+ // 4. Collect Premint using a bad signature
408
+ try {
409
+ await publicClient.simulateContract(
410
+ collectPremintV2WithMintsParams({
411
+ tokenIds: [mintsTokenId],
412
+ quantities: [2n],
413
+ chainId: chainId,
414
+ contractCreationConfig: contractConfig,
415
+ premintConfig: premintConfig,
416
+ mintArguments,
417
+ // put in a bad signature
418
+ premintSignature: "0x",
419
+ account: collectorAccount!,
420
+ }),
421
+ );
422
+ } catch (err) {
423
+ if (err instanceof BaseError) {
424
+ const revertError = err.walk(
425
+ (err) => err instanceof ContractFunctionRevertedError,
426
+ );
427
+ if (revertError instanceof ContractFunctionRevertedError) {
428
+ const errorName = revertError.data?.errorName ?? "";
429
+
430
+ if (errorName === "CallFailed") {
431
+ const decodedInternalError = decodeCallFailedError(revertError);
432
+
433
+ expect(decodedInternalError.errorName).toEqual(
434
+ "InvalidSignature",
435
+ );
436
+ }
437
+ }
438
+ } else {
439
+ throw err;
440
+ }
441
+ }
442
+ },
443
+ );
444
+ anvilTest(
445
+ "can use MINTs to gaslessly collect premint",
446
+ async ({
447
+ viemClients: { walletClient, publicClient, testClient, chain },
448
+ }) => {
449
+ const [collectorAccount, creatorAccount, permitExecutorAccount] =
450
+ await walletClient.getAddresses();
451
+
452
+ const chainId = chain.id as keyof typeof zoraMintsManagerImplAddress;
453
+
454
+ // 1. Create a premint and contract creation config
455
+ const {
456
+ premintConfig,
457
+ contractConfig,
458
+ signature: premintSignature,
459
+ } = await setupContractUsingPremint({
460
+ walletClient,
461
+ publicClient,
462
+ chainId,
463
+ creatorAccount: creatorAccount!,
464
+ });
465
+
466
+ await testClient.setBalance({
467
+ address: collectorAccount!,
468
+ value: parseEther("10"),
469
+ });
470
+
471
+ // 2. Collect some MINTs
472
+ const initialMintsQuantityToMint = 20n;
473
+
474
+ const mintsTokenId = await collectMINTsWithEth({
475
+ publicClient,
476
+ walletClient,
477
+ chainId,
478
+ collectorAccount: collectorAccount!,
479
+ quantityToMint: initialMintsQuantityToMint,
480
+ });
481
+
482
+ const initialMintsBalance = await publicClient.readContract(
483
+ mintsBalanceOfAccountParams({
484
+ account: collectorAccount!,
485
+ chainId: chainId,
486
+ }),
487
+ );
488
+
489
+ // 3. Use MINTS to collect the premint
490
+ const mintArguments: PremintMintArguments = {
491
+ mintComment: "Hi!",
492
+ mintRecipient: collectorAccount!,
493
+ mintRewardsRecipients: [],
494
+ };
495
+
496
+ // 4. Collect Premint using MINT
497
+
498
+ // now sign a message to collect.
499
+ // get random integer:
500
+ const nonce = BigInt(Math.round(Math.random() * 1_000_000));
501
+
502
+ const blockTime = (await publicClient.getBlock()).timestamp;
503
+
504
+ const premintQuantityToCollect = 3n;
505
+
506
+ // make signature deadline 10 seconds from now
507
+ const deadline = blockTime + 10n;
508
+
509
+ // get typed data to sign, as well as permit to collect with
510
+ const { typedData, permit } = collectPremintWithMintsTypedDataDefinition({
511
+ account: collectorAccount!,
512
+ chainId: chainId,
513
+ mintArguments,
514
+ nonce,
515
+ deadline,
516
+ tokenIds: [mintsTokenId],
517
+ quantities: [premintQuantityToCollect],
518
+ contractCreationConfig: contractConfig,
519
+ premintConfig: premintConfig,
520
+ premintSignature: premintSignature,
521
+ });
522
+
523
+ const permitSignature = await walletClient.signTypedData(typedData);
524
+
525
+ // now simulate and execute the transaction
526
+ const permitSimulated = await publicClient.simulateContract({
527
+ ...permitTransferBatchToManagerAndCallParams({
528
+ permit,
529
+ chainId: chainId,
530
+ signature: permitSignature,
531
+ }),
532
+ account: permitExecutorAccount,
533
+ });
534
+
535
+ await waitForSuccess(
536
+ await walletClient.writeContract(permitSimulated.request),
537
+ publicClient,
538
+ );
539
+
540
+ expect(
541
+ await publicClient.readContract(
542
+ mintsBalanceOfAccountParams({
543
+ account: collectorAccount!,
544
+ chainId: chainId,
545
+ }),
546
+ ),
547
+ ).toBe(initialMintsBalance - premintQuantityToCollect);
548
+ },
549
+ );
550
+
551
+ anvilTest(
552
+ "can use MINTs to gaslessly collect on legacy 1155 contracts",
553
+ async ({ viemClients: { walletClient, publicClient, chain } }) => {
554
+ const [collectorAccount, permitExecutorAccount] =
555
+ await walletClient.getAddresses();
556
+
557
+ const chainId = chain.id as keyof typeof zoraMintsManagerImplAddress;
558
+
559
+ // 1. Collect some MINTs
560
+ const initialMintsQuantityToMint = 20n;
561
+
562
+ const mintsTokenId = await collectMINTsWithEth({
563
+ publicClient,
564
+ walletClient,
565
+ chainId,
566
+ collectorAccount: collectorAccount!,
567
+ quantityToMint: initialMintsQuantityToMint,
568
+ });
569
+
570
+ const initialMintsBalance = await publicClient.readContract(
571
+ mintsBalanceOfAccountParams({
572
+ account: collectorAccount!,
573
+ chainId: chainId,
574
+ }),
575
+ );
576
+
577
+ // now sign a message to collect.
578
+ let nonce = BigInt(Math.round(Math.random() * 1_000_000));
579
+
580
+ const blockTime = (await publicClient.getBlock()).timestamp;
581
+
582
+ const quantityToMintOn1155 = 3n;
583
+
584
+ // make signature deadline 10 seconds from now
585
+ const deadline = blockTime + 10n;
586
+
587
+ const fixedPriceMinter = await getFixedPricedMinter({
588
+ publicClient,
589
+ chainId,
590
+ });
591
+
592
+ const tokenId = 1n;
593
+
594
+ const minterArguments = fixedPriceMinterMinterArguments({
595
+ mintRecipient: collectorAccount!,
596
+ });
597
+
598
+ // this is the external contract that will be called
599
+ const legacy1155Address = "0x2988C3b4F3A823488e4E2d70F23bD66366639b81";
600
+
601
+ // this is the external contract funciton that will be called
602
+ const contractCall = encodeFunctionData({
603
+ abi: zoraCreator1155ImplABI,
604
+ functionName: "mint",
605
+ args: [
606
+ fixedPriceMinter,
607
+ tokenId,
608
+ quantityToMintOn1155,
609
+ [],
610
+ minterArguments,
611
+ ],
612
+ });
613
+
614
+ // get typed data to sign, as well as permit to collect with
615
+ const { typedData: batchTransferTypeData, permit: bathTransferPermit } =
616
+ safeTransferBatchAndUnwrapTypedDataDefinition({
617
+ from: collectorAccount!,
618
+ chainId: chainId,
619
+ nonce,
620
+ deadline,
621
+ // token ids to unwrap and burn - must be eth based token ids
622
+ tokenIds: [mintsTokenId],
623
+ // quantities to unwrap and burn
624
+ quantities: [quantityToMintOn1155],
625
+ // external address to call
626
+ addressToCall: legacy1155Address,
627
+ // external contract call
628
+ functionToCall: contractCall,
629
+ // value to send to external contract, extra value from mints
630
+ // will be refunded
631
+ valueToSend: parseEther("0.000777") * quantityToMintOn1155,
632
+ });
633
+
634
+ const permitBatchSignature = await walletClient.signTypedData(
635
+ batchTransferTypeData,
636
+ );
637
+
638
+ // now simulate and execute the transaction
639
+ const permitBatchSimulated = await publicClient.simulateContract({
640
+ ...permitTransferBatchToManagerAndCallParams({
641
+ permit: bathTransferPermit,
642
+ chainId: chainId,
643
+ signature: permitBatchSignature,
644
+ }),
645
+ account: permitExecutorAccount,
646
+ });
647
+
648
+ await waitForSuccess(
649
+ await walletClient.writeContract(permitBatchSimulated.request),
650
+ publicClient,
651
+ );
652
+
653
+ nonce = BigInt(Math.round(Math.random() * 1_000_000));
654
+
655
+ // make non-batch permit and signtarue
656
+ const { typedData: transferTypeData, permit: transferPermit } =
657
+ safeTransferAndUnwrapTypedDataDefinition({
658
+ from: collectorAccount!,
659
+ chainId: chainId,
660
+ nonce,
661
+ deadline,
662
+ // token ids to unwrap and burn - must be eth based token ids
663
+ tokenId: mintsTokenId,
664
+ // quantities to unwrap and burn
665
+ quantity: quantityToMintOn1155,
666
+ // external address to call
667
+ addressToCall: legacy1155Address,
668
+ // external contract call
669
+ functionToCall: contractCall,
670
+ // value to send to external contract, extra value from mints
671
+ // will be refunded
672
+ valueToSend: parseEther("0.000777") * quantityToMintOn1155,
673
+ });
674
+
675
+ const permitSignature =
676
+ await walletClient.signTypedData(transferTypeData);
677
+
678
+ const permitSimulated = await publicClient.simulateContract({
679
+ abi: zoraMints1155ABI,
680
+ address: zoraMints1155Address[chainId],
681
+ functionName: "permitSafeTransfer",
682
+ args: [transferPermit, permitSignature],
683
+ account: permitExecutorAccount,
684
+ });
685
+
686
+ await waitForSuccess(
687
+ await walletClient.writeContract(permitSimulated.request),
688
+ publicClient,
689
+ );
690
+
691
+ expect(
692
+ await publicClient.readContract(
693
+ mintsBalanceOfAccountParams({
694
+ account: collectorAccount!,
695
+ chainId: chainId,
696
+ }),
697
+ ),
698
+ ).toBe(initialMintsBalance - quantityToMintOn1155 * 2n);
699
+
700
+ expect(
701
+ await publicClient.readContract(
702
+ mintsBalanceOfAccountParams({
703
+ account: mintsEthUnwrapperAndCallerConfig.address[chainId],
704
+ chainId: chainId,
705
+ }),
706
+ ),
707
+ ).toBe(0n);
708
+
709
+ const tokenBalance = await publicClient.readContract({
710
+ abi: zoraCreator1155ImplABI,
711
+ address: legacy1155Address,
712
+ functionName: "balanceOf",
713
+ args: [collectorAccount!, tokenId],
714
+ });
715
+
716
+ expect(tokenBalance).toBe(quantityToMintOn1155 * 2n);
717
+ },
718
+ );
719
+ });