@zoralabs/protocol-sdk 0.11.8 → 0.11.10

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 (40) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/CHANGELOG.md +17 -0
  3. package/dist/create/mint-from-create.d.ts +2 -1
  4. package/dist/create/mint-from-create.d.ts.map +1 -1
  5. package/dist/index.cjs +202 -48
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.js +208 -50
  8. package/dist/index.js.map +1 -1
  9. package/dist/mint/mint-client.d.ts +3 -1
  10. package/dist/mint/mint-client.d.ts.map +1 -1
  11. package/dist/mint/mint-queries.d.ts +5 -3
  12. package/dist/mint/mint-queries.d.ts.map +1 -1
  13. package/dist/mint/mint-transactions.d.ts +4 -2
  14. package/dist/mint/mint-transactions.d.ts.map +1 -1
  15. package/dist/premint/premint-client.d.ts +27 -27
  16. package/dist/sdk.d.ts.map +1 -1
  17. package/dist/secondary/secondary-client.d.ts +2 -1
  18. package/dist/secondary/secondary-client.d.ts.map +1 -1
  19. package/dist/secondary/types.d.ts +1 -0
  20. package/dist/secondary/types.d.ts.map +1 -1
  21. package/dist/sparks/sparks-contracts.d.ts +1 -1
  22. package/dist/test-utils.d.ts +5 -1
  23. package/dist/test-utils.d.ts.map +1 -1
  24. package/package.json +4 -4
  25. package/src/comments/comments.test.ts +338 -0
  26. package/src/create/1155-create-helper.test.ts +6 -12
  27. package/src/create/1155-create-helper.ts +2 -0
  28. package/src/create/mint-from-create.ts +3 -0
  29. package/src/create/minter-defaults.ts +7 -7
  30. package/src/mint/mint-client.test.ts +67 -30
  31. package/src/mint/mint-client.ts +10 -1
  32. package/src/mint/mint-queries.ts +16 -5
  33. package/src/mint/mint-transactions.ts +80 -16
  34. package/src/sdk.ts +1 -0
  35. package/src/secondary/secondary-client.test.ts +248 -2
  36. package/src/secondary/secondary-client.ts +136 -6
  37. package/src/secondary/types.ts +2 -0
  38. package/src/sparks/sparks-contracts.ts +1 -1
  39. package/src/sparks/sparks-sponsored-sparks-spender.test.ts +1 -0
  40. package/src/test-utils.ts +19 -0
@@ -36,11 +36,13 @@ export async function getMint({
36
36
  mintGetter,
37
37
  premintGetter,
38
38
  publicClient,
39
+ chainId,
39
40
  }: {
40
41
  params: GetMintParameters;
41
42
  mintGetter: IOnchainMintGetter;
42
43
  premintGetter: IPremintGetter;
43
44
  publicClient: IPublicClient;
45
+ chainId: number;
44
46
  }): Promise<MintableReturn> {
45
47
  const { tokenContract } = params;
46
48
  if (isOnChainMint(params)) {
@@ -53,7 +55,7 @@ export async function getMint({
53
55
  blockTime: blockTime,
54
56
  });
55
57
 
56
- return toMintableReturn(result);
58
+ return toMintableReturn(result, chainId);
57
59
  }
58
60
 
59
61
  const premint = await premintGetter.get({
@@ -103,17 +105,19 @@ export async function getMintsOfContract({
103
105
  mintGetter,
104
106
  premintGetter,
105
107
  publicClient,
108
+ chainId,
106
109
  }: {
107
110
  params: GetMintsOfContractParameters;
108
111
  mintGetter: IOnchainMintGetter;
109
112
  premintGetter: IPremintGetter;
110
113
  publicClient: IPublicClient;
114
+ chainId: number;
111
115
  }): Promise<{ contract?: ContractInfo; tokens: MintableReturn[] }> {
112
116
  const onchainMints = (
113
117
  await mintGetter.getContractMintable({
114
118
  tokenAddress: params.tokenContract,
115
119
  })
116
- ).map(toMintableReturn);
120
+ ).map((result) => toMintableReturn(result, chainId));
117
121
 
118
122
  const offchainMints = await getPremintsOfContractMintable({
119
123
  mintGetter,
@@ -270,7 +274,7 @@ function parsePremint({
270
274
  }
271
275
 
272
276
  export const makeOnchainPrepareMint =
273
- (result: OnchainSalesConfigAndTokenInfo): PrepareMint =>
277
+ (result: OnchainSalesConfigAndTokenInfo, chainId: number): PrepareMint =>
274
278
  (params: MintParametersBase) => {
275
279
  if (!result.salesConfig) {
276
280
  throw new Error("No valid sales config found for token");
@@ -280,6 +284,7 @@ export const makeOnchainPrepareMint =
280
284
  parameters: makeOnchainMintCall({
281
285
  token: result as Concrete<OnchainSalesConfigAndTokenInfo>,
282
286
  mintParams: params,
287
+ chainId,
283
288
  }),
284
289
  erc20Approval: getRequiredErc20Approvals(params, result.salesConfig),
285
290
  costs: parseMintCosts({
@@ -290,7 +295,10 @@ export const makeOnchainPrepareMint =
290
295
  };
291
296
  };
292
297
 
293
- function toMintableReturn(result: GetMintableReturn): MintableReturn {
298
+ function toMintableReturn(
299
+ result: GetMintableReturn,
300
+ chainId: number,
301
+ ): MintableReturn {
294
302
  const primaryMintActive = result.primaryMintActive;
295
303
  if (!primaryMintActive) {
296
304
  return {
@@ -306,7 +314,10 @@ function toMintableReturn(result: GetMintableReturn): MintableReturn {
306
314
  primaryMintActive,
307
315
  primaryMintEnd: result.primaryMintEnd,
308
316
  secondaryMarketActive: result.secondaryMarketActive,
309
- prepareMint: makeOnchainPrepareMint(result.salesConfigAndTokenInfo),
317
+ prepareMint: makeOnchainPrepareMint(
318
+ result.salesConfigAndTokenInfo,
319
+ chainId,
320
+ ),
310
321
  };
311
322
  }
312
323
 
@@ -11,6 +11,8 @@ import {
11
11
  erc20MinterABI,
12
12
  zoraCreator1155ImplABI,
13
13
  zoraTimedSaleStrategyABI,
14
+ callerAndCommenterABI,
15
+ callerAndCommenterAddress,
14
16
  } from "@zoralabs/protocol-deployments";
15
17
  import { zora721Abi, zora1155LegacyAbi } from "src/constants";
16
18
  import {
@@ -32,9 +34,11 @@ import { AllowListEntry } from "src/allow-list/types";
32
34
  export function makeOnchainMintCall({
33
35
  token,
34
36
  mintParams,
37
+ chainId,
35
38
  }: {
36
39
  token: Concrete<OnchainSalesConfigAndTokenInfo>;
37
40
  mintParams: Omit<MakeMintParametersArgumentsBase, "tokenContract">;
41
+ chainId: number;
38
42
  }): SimulateContractParametersWithAccount {
39
43
  if (token.mintType === "721") {
40
44
  return makePrepareMint721TokenParams({
@@ -48,6 +52,7 @@ export function makeOnchainMintCall({
48
52
  salesConfigAndTokenInfo: token,
49
53
  tokenContract: token.contract.address,
50
54
  tokenId: token.tokenId!,
55
+ chainId,
51
56
  ...mintParams,
52
57
  });
53
58
  }
@@ -57,6 +62,69 @@ export type MintableParameters = Pick<
57
62
  "contractVersion" | "salesConfig"
58
63
  >;
59
64
 
65
+ function makeZoraTimedSaleStrategyMintCall({
66
+ minterAccount,
67
+ salesConfigAndTokenInfo,
68
+ mintQuantity,
69
+ mintTo,
70
+ tokenContract,
71
+ tokenId,
72
+ mintReferral,
73
+ mintComment,
74
+ chainId,
75
+ }: {
76
+ minterAccount: Address | Account;
77
+ salesConfigAndTokenInfo: Concrete<MintableParameters>;
78
+ mintQuantity: bigint;
79
+ mintTo: Address;
80
+ tokenContract: Address;
81
+ tokenId: GenericTokenIdTypes;
82
+ mintReferral?: Address;
83
+ mintComment?: string;
84
+ chainId: number;
85
+ }) {
86
+ // if there is a mint comment, use the caller and commenter
87
+ if (mintComment && mintComment !== "") {
88
+ return makeContractParameters({
89
+ abi: callerAndCommenterABI,
90
+ address:
91
+ callerAndCommenterAddress[
92
+ chainId as keyof typeof callerAndCommenterAddress
93
+ ],
94
+ functionName: "timedSaleMintAndComment",
95
+ account: minterAccount,
96
+ value:
97
+ salesConfigAndTokenInfo.salesConfig.mintFeePerQuantity * mintQuantity,
98
+ args: [
99
+ mintTo,
100
+ mintQuantity,
101
+ tokenContract,
102
+ tokenId,
103
+ mintReferral || zeroAddress,
104
+ mintComment,
105
+ ],
106
+ });
107
+ }
108
+
109
+ return makeContractParameters({
110
+ abi: zoraTimedSaleStrategyABI,
111
+ functionName: "mint",
112
+ account: minterAccount,
113
+ address: salesConfigAndTokenInfo.salesConfig.address,
114
+ value:
115
+ salesConfigAndTokenInfo.salesConfig.mintFeePerQuantity * mintQuantity,
116
+ /* args: mintTo, quantity, collection, tokenId, mintReferral, comment */
117
+ args: [
118
+ mintTo,
119
+ mintQuantity,
120
+ tokenContract,
121
+ BigInt(tokenId),
122
+ mintReferral || zeroAddress,
123
+ "",
124
+ ],
125
+ });
126
+ }
127
+
60
128
  export function makePrepareMint1155TokenParams({
61
129
  tokenContract: tokenContract,
62
130
  tokenId,
@@ -67,9 +135,11 @@ export function makePrepareMint1155TokenParams({
67
135
  mintRecipient,
68
136
  quantityToMint,
69
137
  allowListEntry,
138
+ chainId,
70
139
  }: {
71
140
  salesConfigAndTokenInfo: Concrete<MintableParameters>;
72
141
  tokenId: GenericTokenIdTypes;
142
+ chainId: number;
73
143
  } & Pick<
74
144
  MakeMintParametersArgumentsBase,
75
145
  | "minterAccount"
@@ -101,22 +171,16 @@ export function makePrepareMint1155TokenParams({
101
171
  }
102
172
 
103
173
  if (saleType === "timed") {
104
- return makeContractParameters({
105
- abi: zoraTimedSaleStrategyABI,
106
- functionName: "mint",
107
- account: minterAccount,
108
- address: salesConfigAndTokenInfo.salesConfig.address,
109
- value:
110
- salesConfigAndTokenInfo.salesConfig.mintFeePerQuantity * mintQuantity,
111
- /* args: mintTo, quantity, collection, tokenId, mintReferral, comment */
112
- args: [
113
- mintTo,
114
- mintQuantity,
115
- tokenContract,
116
- BigInt(tokenId),
117
- mintReferral || zeroAddress,
118
- mintComment || "",
119
- ],
174
+ return makeZoraTimedSaleStrategyMintCall({
175
+ minterAccount,
176
+ salesConfigAndTokenInfo,
177
+ mintQuantity,
178
+ mintTo,
179
+ tokenContract,
180
+ tokenId,
181
+ mintReferral,
182
+ mintComment,
183
+ chainId,
120
184
  });
121
185
  }
122
186
 
package/src/sdk.ts CHANGED
@@ -116,6 +116,7 @@ export function createCollectorClient(
116
116
  publicClient: params.publicClient,
117
117
  premintGetter: premintGetterToUse,
118
118
  mintGetter: mintGetterToUse,
119
+ chainId: params.chainId,
119
120
  });
120
121
  const secondaryClient = new SecondaryClient({
121
122
  publicClient: params.publicClient,
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, vi } from "vitest";
2
- import { parseEther, Address } from "viem";
2
+ import { parseEther, Address, parseEventLogs } from "viem";
3
3
  import { zoraSepolia } from "viem/chains";
4
4
  import {
5
5
  forkUrls,
@@ -7,13 +7,22 @@ import {
7
7
  simulateAndWriteContractWithRetries,
8
8
  } from "src/anvil";
9
9
  import { createCollectorClient } from "src/sdk";
10
- import { zoraCreator1155ImplABI } from "@zoralabs/protocol-deployments";
10
+ import {
11
+ zoraCreator1155ImplABI,
12
+ commentsABI,
13
+ callerAndCommenterABI,
14
+ PermitBuyOnSecondaryAndComment,
15
+ permitBuyOnSecondaryAndCommentTypedDataDefinition,
16
+ callerAndCommenterAddress,
17
+ sparkValue,
18
+ } from "@zoralabs/protocol-deployments";
11
19
  import { SubgraphMintGetter } from "src/mint/subgraph-mint-getter";
12
20
  import { ERROR_SECONDARY_NOT_STARTED } from "./secondary-client";
13
21
  import { ISubgraphQuerier } from "src/apis/subgraph-querier";
14
22
  import { mockTimedSaleStrategyTokenQueryResult } from "src/fixtures/mint-query-results";
15
23
  import { new1155ContractVersion } from "src/create/contract-setup";
16
24
  import { advanceToSaleAndAndLaunchMarket } from "src/fixtures/secondary";
25
+ import { randomNonce } from "src/test-utils";
17
26
 
18
27
  describe("secondary", () => {
19
28
  makeAnvilTest({
@@ -257,4 +266,241 @@ describe("secondary", () => {
257
266
  },
258
267
  30_000,
259
268
  );
269
+
270
+ makeAnvilTest({
271
+ forkBlockNumber: 16339853,
272
+ forkUrl: forkUrls.zoraSepolia,
273
+ anvilChainId: zoraSepolia.id,
274
+ })(
275
+ "it can buy on secondary with a comment",
276
+ async ({
277
+ viemClients: { publicClient, chain, walletClient, testClient },
278
+ }) => {
279
+ const collectorAccount = (await walletClient.getAddresses()!)[1]!;
280
+ const executorAccount = (await walletClient.getAddresses()!)[3]!;
281
+
282
+ const mintGetter = new SubgraphMintGetter(chain.id);
283
+ const contractAddress: Address =
284
+ "0xd42557f24034b53e7340a40bb5813ef9ba88f2b4";
285
+ const newTokenId = 4n;
286
+
287
+ await testClient.setBalance({
288
+ address: collectorAccount,
289
+ value: parseEther("100"),
290
+ });
291
+
292
+ mintGetter.subgraphQuerier.query = vi
293
+ .fn<ISubgraphQuerier["query"]>()
294
+ .mockResolvedValue({
295
+ zoraCreateToken: mockTimedSaleStrategyTokenQueryResult({
296
+ chainId: chain.id,
297
+ tokenId: newTokenId,
298
+ contractAddress,
299
+ contractVersion:
300
+ new1155ContractVersion[
301
+ chain.id as keyof typeof new1155ContractVersion
302
+ ],
303
+ }),
304
+ });
305
+
306
+ const collectorClient = createCollectorClient({
307
+ chainId: chain.id,
308
+ publicClient,
309
+ mintGetter,
310
+ });
311
+
312
+ const secondaryInfo = await collectorClient.getSecondaryInfo({
313
+ contract: contractAddress,
314
+ tokenId: newTokenId,
315
+ });
316
+
317
+ // mint enough to start the countdown
318
+ const quantityToMint =
319
+ secondaryInfo!.minimumMintsForCountdown! - secondaryInfo!.mintCount;
320
+
321
+ const { parameters: collectParameters } = await collectorClient.mint({
322
+ minterAccount: collectorAccount,
323
+ mintType: "1155",
324
+ quantityToMint: quantityToMint,
325
+ tokenId: newTokenId,
326
+ tokenContract: contractAddress,
327
+ });
328
+
329
+ await simulateAndWriteContractWithRetries({
330
+ parameters: collectParameters,
331
+ walletClient,
332
+ publicClient,
333
+ });
334
+
335
+ await advanceToSaleAndAndLaunchMarket({
336
+ contractAddress,
337
+ tokenId: newTokenId,
338
+ testClient,
339
+ publicClient,
340
+ walletClient,
341
+ collectorClient,
342
+ chainId: chain.id,
343
+ account: collectorAccount,
344
+ });
345
+
346
+ const buyResult = await collectorClient.buy1155OnSecondary({
347
+ account: collectorAccount,
348
+ quantity: 5n,
349
+ contract: contractAddress,
350
+ tokenId: newTokenId,
351
+ comment: "test comment",
352
+ });
353
+
354
+ const receipt = await simulateAndWriteContractWithRetries({
355
+ parameters: buyResult.parameters!,
356
+ walletClient,
357
+ publicClient,
358
+ });
359
+
360
+ const commentedEvent = parseEventLogs({
361
+ abi: commentsABI,
362
+ logs: receipt.logs,
363
+ eventName: "Commented",
364
+ });
365
+
366
+ expect(commentedEvent[0]).toBeDefined();
367
+ expect(commentedEvent[0]!.args.text).toBe("test comment");
368
+
369
+ const boughtAndCommentedEvent = parseEventLogs({
370
+ abi: callerAndCommenterABI,
371
+ logs: receipt.logs,
372
+ eventName: "SwappedOnSecondaryAndCommented",
373
+ });
374
+
375
+ expect(boughtAndCommentedEvent[0]).toBeDefined();
376
+ expect(boughtAndCommentedEvent[0]!.args.comment).toBe("test comment");
377
+ expect(boughtAndCommentedEvent[0]!.args.quantity).toBe(5n);
378
+ expect(boughtAndCommentedEvent[0]!.args.swapDirection).toBe(0);
379
+
380
+ // PERMIT BUY TEST
381
+ const buyResultASecondTime = await collectorClient.buy1155OnSecondary({
382
+ account: collectorAccount,
383
+ quantity: 5n,
384
+ contract: contractAddress,
385
+ tokenId: newTokenId,
386
+ comment: "test comment",
387
+ });
388
+
389
+ const valueToSend = (buyResultASecondTime.price!.wei.total * 105n) / 100n;
390
+
391
+ const { timestamp } = await publicClient.getBlock();
392
+
393
+ const permitBuy: PermitBuyOnSecondaryAndComment = {
394
+ collection: contractAddress,
395
+ tokenId: newTokenId,
396
+ quantity: 5n,
397
+ commenter: collectorAccount,
398
+ comment: "test comment",
399
+ maxEthToSpend: valueToSend,
400
+ deadline: timestamp + 30n,
401
+ sqrtPriceLimitX96: 0n,
402
+ nonce: randomNonce(),
403
+ sourceChainId: chain.id,
404
+ destinationChainId: chain.id,
405
+ };
406
+
407
+ const permitBuySignature = await walletClient.signTypedData(
408
+ permitBuyOnSecondaryAndCommentTypedDataDefinition(permitBuy),
409
+ );
410
+
411
+ await testClient.setBalance({
412
+ address: executorAccount,
413
+ value: parseEther("1"),
414
+ });
415
+
416
+ const { request } = await publicClient.simulateContract({
417
+ abi: callerAndCommenterABI,
418
+ address:
419
+ callerAndCommenterAddress[
420
+ chain.id as keyof typeof callerAndCommenterAddress
421
+ ],
422
+ functionName: "permitBuyOnSecondaryAndComment",
423
+ args: [permitBuy, permitBuySignature],
424
+ value: valueToSend,
425
+ account: executorAccount,
426
+ });
427
+
428
+ await simulateAndWriteContractWithRetries({
429
+ parameters: request,
430
+ walletClient,
431
+ publicClient,
432
+ });
433
+
434
+ // now PERMIT SELL ON SECONDARY TEST
435
+ const quantityToSell = 3n;
436
+
437
+ const sellResult = await collectorClient.sell1155OnSecondary({
438
+ account: collectorAccount,
439
+ quantity: quantityToSell,
440
+ contract: contractAddress,
441
+ tokenId: newTokenId,
442
+ });
443
+
444
+ expect(sellResult.error).toBeUndefined();
445
+
446
+ // approve 1155s for callerAndCommenter to transfer, when selling
447
+ await simulateAndWriteContractWithRetries({
448
+ parameters: {
449
+ abi: zoraCreator1155ImplABI,
450
+ address: contractAddress,
451
+ functionName: "setApprovalForAll",
452
+ account: collectorAccount,
453
+ args: [
454
+ callerAndCommenterAddress[
455
+ chain.id as keyof typeof callerAndCommenterAddress
456
+ ],
457
+ true,
458
+ ],
459
+ },
460
+ walletClient,
461
+ publicClient,
462
+ });
463
+
464
+ // now sell on secondary with comment
465
+ // by calling the caller and commenter contract
466
+ // if including a comment, must send sparkValue() as value
467
+ // function signature:
468
+ // function sellOnSecondaryAndComment(
469
+ // address commenter,
470
+ // uint256 quantity,
471
+ // address collection,
472
+ // uint256 tokenId,
473
+ // address payable recipient,
474
+ // uint256 minEthToAcquire,
475
+ // uint160 sqrtPriceLimitX96,
476
+ // string calldata comment
477
+ // )
478
+ await simulateAndWriteContractWithRetries({
479
+ parameters: {
480
+ abi: callerAndCommenterABI,
481
+ address:
482
+ callerAndCommenterAddress[
483
+ chain.id as keyof typeof callerAndCommenterAddress
484
+ ],
485
+ functionName: "sellOnSecondaryAndComment",
486
+ account: collectorAccount,
487
+ args: [
488
+ collectorAccount,
489
+ quantityToSell,
490
+ contractAddress,
491
+ newTokenId,
492
+ collectorAccount,
493
+ // sell result with slippage
494
+ (sellResult.price!.wei.total * 95n) / 100n,
495
+ 0n,
496
+ "test comment",
497
+ ],
498
+ value: sparkValue(),
499
+ },
500
+ walletClient,
501
+ publicClient,
502
+ });
503
+ },
504
+ 20_000,
505
+ );
260
506
  });