@zoralabs/protocol-sdk 0.7.3-SPARKS.0 → 0.7.4

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 (46) hide show
  1. package/.turbo/turbo-build.log +18 -0
  2. package/CHANGELOG.md +17 -4
  3. package/LICENSE +21 -0
  4. package/dist/anvil.d.ts +2 -2
  5. package/dist/anvil.d.ts.map +1 -1
  6. package/dist/apis/http-api-base.d.ts.map +1 -1
  7. package/dist/index.cjs +2265 -319
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.js +2289 -320
  10. package/dist/index.js.map +1 -1
  11. package/dist/ipfs/token-metadata.d.ts.map +1 -1
  12. package/dist/mint/mint-client.d.ts +1 -1
  13. package/dist/mint/mint-queries.d.ts +1 -1
  14. package/dist/mint/types.d.ts.map +1 -1
  15. package/dist/mints/mints-contracts.d.ts +1 -1
  16. package/dist/mints/mints-contracts.d.ts.map +1 -1
  17. package/dist/mints/mints-eth-unwrapper-and-caller.d.ts.map +1 -1
  18. package/dist/mints/mints-queries.d.ts.map +1 -1
  19. package/dist/mints/mints-relay-example.d.ts +7 -7
  20. package/dist/mints/mints-relay-example.d.ts.map +1 -1
  21. package/dist/premint/conversions.d.ts +5 -5
  22. package/dist/premint/conversions.d.ts.map +1 -1
  23. package/dist/premint/premint-api-client.d.ts +1 -1
  24. package/dist/premint/premint-api-client.d.ts.map +1 -1
  25. package/dist/premint/premint-client.d.ts +4 -4
  26. package/dist/premint/premint-client.d.ts.map +1 -1
  27. package/dist/premint/preminter.d.ts +3 -3
  28. package/dist/premint/preminter.d.ts.map +1 -1
  29. package/dist/preminter.d.ts +2 -2
  30. package/dist/preminter.d.ts.map +1 -1
  31. package/dist/test-utils.d.ts.map +1 -1
  32. package/package.json +21 -16
  33. package/src/create/1155-create-helper.test.ts +325 -0
  34. package/src/mint/mint-client.test.ts +263 -0
  35. package/src/mints/mints-contracts.test.ts +529 -0
  36. package/src/mints/mints-eth-unwrapper-and-caller.test.ts +467 -0
  37. package/src/mints/mints-eth-unwrapper-and-caller.ts +2 -2
  38. package/src/mints/mints-queries.test.ts +105 -0
  39. package/src/mints/mints-relay-example.ts +22 -13
  40. package/src/premint/premint-client.test.ts +290 -0
  41. package/src/premint/preminter.test.ts +866 -0
  42. package/test-integration/setup-test-contracts.ts +96 -0
  43. package/tsconfig.build.json +10 -0
  44. package/tsconfig.json +1 -1
  45. package/tsup.config.ts +12 -0
  46. package/yarn-error.log +0 -8602
@@ -0,0 +1,467 @@
1
+ import { describe, expect } from "vitest";
2
+
3
+ import { forkUrls, makeAnvilTest } from "src/anvil";
4
+ import {
5
+ mintsEthUnwrapperAndCallerABI,
6
+ mintsEthUnwrapperAndCallerAddress,
7
+ mintsEthUnwrapperAndCallerConfig,
8
+ zoraCreator1155ImplABI,
9
+ zoraMints1155ABI,
10
+ zoraMints1155Address,
11
+ zoraMintsManagerImplAddress,
12
+ } from "@zoralabs/protocol-deployments";
13
+ import {
14
+ Address,
15
+ Hex,
16
+ PublicClient,
17
+ encodeFunctionData,
18
+ parseEther,
19
+ } from "viem";
20
+ import { mintsBalanceOfAccountParams } from "./mints-contracts";
21
+ import { base, zora, zoraSepolia } from "viem/chains";
22
+ import {
23
+ getRelayCall,
24
+ makeAndSignSponsoredRelayCall,
25
+ validateAndExecuteSponsoredRelayCall,
26
+ } from "./mints-relay-example";
27
+ import { collectMINTsWithEth } from "./mints-contracts.test";
28
+ import {
29
+ fixedPriceMinterMinterArguments,
30
+ getFixedPricedMinter,
31
+ waitForSuccess,
32
+ } from "src/test-utils";
33
+ import { unwrapAndForwardEthPermitAndTypedDataDefinition } from "./mints-eth-unwrapper-and-caller";
34
+
35
+ const randomNonce = (): bigint => BigInt(Math.round(Math.random() * 1_000_000));
36
+
37
+ const anvilTest = makeAnvilTest({
38
+ forkUrl: forkUrls.zoraMainnet,
39
+ forkBlockNumber: 12990454,
40
+ anvilChainId: zora.id,
41
+ });
42
+
43
+ const makeLegacy1155MintCall = async ({
44
+ publicClient,
45
+ chainId,
46
+ mintRecipient,
47
+ tokenId,
48
+ quantityToMint,
49
+ }: {
50
+ publicClient: PublicClient;
51
+ chainId: keyof typeof zoraMints1155Address;
52
+ mintRecipient: Address;
53
+ tokenId: bigint;
54
+ quantityToMint: bigint;
55
+ }) => {
56
+ const fixedPriceMinter = await getFixedPricedMinter({
57
+ publicClient,
58
+ chainId,
59
+ });
60
+ const minterArguments = fixedPriceMinterMinterArguments({
61
+ mintRecipient,
62
+ });
63
+
64
+ // this is the external contract function that will be called
65
+ // by relay on the other chain
66
+ const mintCall = encodeFunctionData({
67
+ abi: zoraCreator1155ImplABI,
68
+ functionName: "mint",
69
+ args: [fixedPriceMinter, tokenId, quantityToMint, [], minterArguments],
70
+ });
71
+ // amount of eth required to mint the quantity of tokens on the other chain.
72
+ // this value will be bridged by relay and passed through to the target
73
+ // contract on the destination chain.
74
+ const mintFee = parseEther("0.000777") * quantityToMint;
75
+
76
+ return {
77
+ mintCall,
78
+ mintFee,
79
+ };
80
+ };
81
+
82
+ describe("MintsEthUnwrapperAndCaller", () => {
83
+ makeAnvilTest({
84
+ forkUrl: forkUrls.zoraSepolia,
85
+ forkBlockNumber: 7297306,
86
+ anvilChainId: zoraSepolia.id,
87
+ })(
88
+ "can be used to gaslessly unwrap MINTs values and collect older versions of 1155 contracts",
89
+ async ({ viemClients: { walletClient, publicClient, chain } }) => {
90
+ const [collectorAccount, permitExecutorAccount] =
91
+ await walletClient.getAddresses();
92
+
93
+ const chainId = chain.id as keyof typeof zoraMintsManagerImplAddress;
94
+
95
+ // 1. Collect some MINTs
96
+ const initialMintsQuantityToMint = 20n;
97
+
98
+ const mintsTokenId = await collectMINTsWithEth({
99
+ publicClient,
100
+ walletClient,
101
+ chainId,
102
+ collectorAccount: collectorAccount!,
103
+ quantityToMint: initialMintsQuantityToMint,
104
+ });
105
+
106
+ const initialMintsBalance = await publicClient.readContract(
107
+ mintsBalanceOfAccountParams({
108
+ account: collectorAccount!,
109
+ chainId: chainId,
110
+ }),
111
+ );
112
+
113
+ const quantityToMintOn1155 = 3n;
114
+
115
+ const tokenId = 1n;
116
+
117
+ // this is the external contract that will be called
118
+ const legacy1155Address = "0x2988C3b4F3A823488e4E2d70F23bD66366639b81";
119
+
120
+ const { mintCall: contractCall, mintFee } = await makeLegacy1155MintCall({
121
+ chainId,
122
+ mintRecipient: collectorAccount!,
123
+ tokenId,
124
+ quantityToMint: quantityToMintOn1155,
125
+ publicClient,
126
+ });
127
+
128
+ // get typed data to sign, as well as permit to collect with
129
+ const { typedData: batchTransferTypeData, permit: batchTransferPermit } =
130
+ unwrapAndForwardEthPermitAndTypedDataDefinition({
131
+ from: collectorAccount!,
132
+ chainId: chainId,
133
+ nonce: randomNonce(),
134
+ deadline: (await publicClient.getBlock()).timestamp + 10n,
135
+ // token ids to unwrap and burn - must be eth based token ids
136
+ tokenIds: [mintsTokenId],
137
+ // quantities to unwrap and burn
138
+ quantities: [quantityToMintOn1155],
139
+ callWithEth: {
140
+ // external address to call
141
+ address: legacy1155Address,
142
+ // external contract call
143
+ call: contractCall,
144
+ // value to send to external contract, extra value from mints
145
+ // will be refunded
146
+ value: mintFee,
147
+ },
148
+ });
149
+
150
+ const permitBatchSignature = await walletClient.signTypedData(
151
+ batchTransferTypeData,
152
+ );
153
+
154
+ // now simulate and execute the transaction
155
+ const permitBatchSimulated = await publicClient.simulateContract({
156
+ abi: zoraMints1155ABI,
157
+ address: zoraMints1155Address[chainId],
158
+ functionName: "permitSafeTransferBatch",
159
+ args: [batchTransferPermit, permitBatchSignature],
160
+ account: permitExecutorAccount,
161
+ });
162
+
163
+ await waitForSuccess(
164
+ await walletClient.writeContract(permitBatchSimulated.request),
165
+ publicClient,
166
+ );
167
+
168
+ expect(
169
+ await publicClient.readContract(
170
+ mintsBalanceOfAccountParams({
171
+ account: collectorAccount!,
172
+ chainId: chainId,
173
+ }),
174
+ ),
175
+ ).toBe(initialMintsBalance - quantityToMintOn1155);
176
+
177
+ expect(
178
+ await publicClient.readContract(
179
+ mintsBalanceOfAccountParams({
180
+ account: mintsEthUnwrapperAndCallerConfig.address[chainId],
181
+ chainId: chainId,
182
+ }),
183
+ ),
184
+ ).toBe(0n);
185
+
186
+ const tokenBalance = await publicClient.readContract({
187
+ abi: zoraCreator1155ImplABI,
188
+ address: legacy1155Address,
189
+ functionName: "balanceOf",
190
+ args: [collectorAccount!, tokenId],
191
+ });
192
+
193
+ expect(tokenBalance).toBe(quantityToMintOn1155);
194
+ },
195
+ 20_000,
196
+ );
197
+
198
+ anvilTest(
199
+ "can be used gaslessly to unwrap MINTs values and collect on other chains using Relay",
200
+ async ({ viemClients: { walletClient, publicClient, chain } }) => {
201
+ // this test shows how an account can unwrap eth value of MINTs
202
+ // and use relay to mint a zora creator 1155 token on another chain.
203
+
204
+ // it does this by:
205
+ // 1. getting the relay call to make on the other chain
206
+ // 2. signing a permit to transfer the MINTs to the eth unwrapper and caller,
207
+ // and using that unwrapped value to call relay with the unwrapped value.
208
+ // 3. Executing a transaction on the mintsEthUnwrapperAndCaller by passing
209
+ // in the permit, signature, and relay fee as the payable value,
210
+ // which unwraps the transferred MINTs eth, adds the relay fee, and calls
211
+ // relay with that value.
212
+ const [collectorAccount, permitExecutorAccount] =
213
+ await walletClient.getAddresses();
214
+
215
+ const chainId = chain.id as keyof typeof zoraMintsManagerImplAddress;
216
+
217
+ const initialMintsQuantityToMint = 20n;
218
+
219
+ const mintsTokenId = await collectMINTsWithEth({
220
+ publicClient,
221
+ walletClient,
222
+ chainId,
223
+ collectorAccount: collectorAccount!,
224
+ quantityToMint: initialMintsQuantityToMint,
225
+ });
226
+
227
+ const tokenId = 6n;
228
+
229
+ const quantityToMint = 3n;
230
+
231
+ const destinationChainId = base.id;
232
+
233
+ // address of the 1155 contract on the other chain that will be called
234
+ const destinationContractAddress =
235
+ "0x5f69da5da41e5472afb88fc291e7a92b7f15fbc5" as Address;
236
+
237
+ const { mintCall, mintFee: mintFeeOnOtherChain } =
238
+ await makeLegacy1155MintCall({
239
+ publicClient,
240
+ chainId,
241
+ mintRecipient: collectorAccount!,
242
+ tokenId,
243
+ quantityToMint,
244
+ });
245
+
246
+ // build the cross chain relay call by requesting it from their api.
247
+ // this will give: address to call, data to send in call, and value to send
248
+ // returns the call to relay, and how much of the value being sent to them is the fee
249
+ const { relayCall: relayCall, relayFee: relayFee } = await getRelayCall({
250
+ // the mints eth unwrapper and caller contract is the account
251
+ // that is doing to be depositing the eth value into relay
252
+ depositingAccount: mintsEthUnwrapperAndCallerAddress[chainId],
253
+ // the chain to call from (current chain)
254
+ originChainId: chain.id,
255
+ // the chain that the call will be executed on
256
+ toChainId: destinationChainId,
257
+ // the tx to call on the other chain:
258
+ tx: {
259
+ to: destinationContractAddress,
260
+ value: mintFeeOnOtherChain,
261
+ data: mintCall,
262
+ },
263
+ });
264
+
265
+ // build permit to transfer mints to the mintsEthUnwrapperAndCaller,
266
+ // and call the relay with the unwrapped value.
267
+ // get data to be signed
268
+ const { typedData: transferTypeData, permit: transferPermit } =
269
+ unwrapAndForwardEthPermitAndTypedDataDefinition({
270
+ // mints will be transferred from this account
271
+ from: collectorAccount!,
272
+ chainId: chainId,
273
+ // random nonce
274
+ nonce: randomNonce(),
275
+ // deadling for signature
276
+ deadline: (await publicClient.getBlock()).timestamp + 100n,
277
+ // token ids to unwrap and burn - must be eth based token ids
278
+ tokenIds: [mintsTokenId],
279
+ // quantities to unwrap and burn
280
+ quantities: [quantityToMint],
281
+ callWithEth: {
282
+ // external address to call
283
+ address: relayCall.to,
284
+ // external contract call
285
+ call: relayCall.data as Hex,
286
+ // value to send to external contract, extra value from mints
287
+ // will be refunded
288
+ value: BigInt(relayCall.value),
289
+ },
290
+ });
291
+
292
+ // sign the permit
293
+ const permitSignature =
294
+ await walletClient.signTypedData(transferTypeData);
295
+
296
+ const collectorBalanceBefore = await publicClient.getBalance({
297
+ address: collectorAccount!,
298
+ });
299
+
300
+ const collectorMintsBalanceBefore = await publicClient.readContract(
301
+ mintsBalanceOfAccountParams({
302
+ account: collectorAccount!,
303
+ chainId: chainId,
304
+ }),
305
+ );
306
+
307
+ // now we call a payable function on the mints eth unwrapper and caller contract,
308
+ // with the permit and corresponding signature to transfer the mints to the unwrapper,
309
+ // and call relay with the unwrapped value + relay fee.
310
+ // the payable value on this call is the relay fee, which is added to the unwrapped
311
+ // value of the mints and sent to the other chain.
312
+ // any remaining value from the unwrapped MINTs is refunded to the original caller.
313
+ const simulated = await publicClient.simulateContract({
314
+ abi: mintsEthUnwrapperAndCallerABI,
315
+ address: mintsEthUnwrapperAndCallerAddress[chainId],
316
+ functionName: "permitWithAdditionalValue",
317
+ args: [transferPermit, permitSignature],
318
+ account: permitExecutorAccount!,
319
+ // we must call this functio
320
+ value: relayFee,
321
+ });
322
+
323
+ // wait for the transaction to succeed.
324
+ await waitForSuccess(
325
+ await walletClient.writeContract(simulated.request),
326
+ publicClient,
327
+ );
328
+
329
+ const ethUnwrapperBalance = await publicClient.getBalance({
330
+ address: mintsEthUnwrapperAndCallerAddress[chainId],
331
+ });
332
+
333
+ // check that no remaining eth is left in the unwrapper
334
+ expect(ethUnwrapperBalance).toBe(0n);
335
+
336
+ // collector balance should not have changed
337
+ expect(
338
+ await publicClient.getBalance({
339
+ address: collectorAccount!,
340
+ }),
341
+ ).toBe(collectorBalanceBefore);
342
+
343
+ expect(
344
+ await publicClient.readContract(
345
+ mintsBalanceOfAccountParams({
346
+ account: collectorAccount!,
347
+ chainId: chainId,
348
+ }),
349
+ ),
350
+ ).toBe(collectorMintsBalanceBefore - quantityToMint);
351
+ },
352
+ 10_000,
353
+ );
354
+ anvilTest(
355
+ "can be used gaslessly to unwrap MINTs values and collect on other chains using Relay with a signature by the executor",
356
+ async ({ viemClients: { walletClient, publicClient, chain } }) => {
357
+ // this is similar to the above test, but it shows how the executor
358
+ // can sign a message indicating its willing to do the said relay call and pay the extra relay fee,
359
+ // with a deadline.
360
+ // this is a flow starts with a relay call being done on a server, and an executing account
361
+ // signing a message indicating its willing to execute that call and pay the relay fee.
362
+ // It the returns this call to the client, and the client signs the permit to transfer the mints
363
+ // with that call.
364
+ // That signature, premit, and original signature with deadline are then passed to the server,
365
+ // the server validates the original signature, checks the deadlined hasn't passed, and then executes the relay call,
366
+ // paying the relay fee.
367
+ const [collectorAccount, permitExecutorAccount] =
368
+ await walletClient.getAddresses();
369
+
370
+ const chainId = chain.id as keyof typeof zoraMintsManagerImplAddress;
371
+
372
+ const initialMintsQuantityToMint = 20n;
373
+
374
+ const mintsTokenId = await collectMINTsWithEth({
375
+ publicClient,
376
+ walletClient,
377
+ chainId,
378
+ collectorAccount: collectorAccount!,
379
+ quantityToMint: initialMintsQuantityToMint,
380
+ });
381
+
382
+ const tokenId = 6n;
383
+
384
+ const quantityToMint = 3n;
385
+
386
+ const destinationChainId = base.id;
387
+
388
+ // address of the 1155 contract on the other chain that will be called
389
+ const destinationContractAddress =
390
+ "0x5f69da5da41e5472afb88fc291e7a92b7f15fbc5" as Address;
391
+
392
+ const { mintCall, mintFee: mintFeeOnOtherChain } =
393
+ await makeLegacy1155MintCall({
394
+ publicClient,
395
+ chainId,
396
+ mintRecipient: collectorAccount!,
397
+ tokenId,
398
+ quantityToMint,
399
+ });
400
+
401
+ // this call would happen on the server, which would call relay, and generate
402
+ // data to sign for the permit. It would also sign a message indicating it would be willing
403
+ // to pay the relay fee. This signature is used later.
404
+ const {
405
+ safeTransferData,
406
+ signature: sponsoredRelayCallSignature,
407
+ deadline,
408
+ additionalValueToSend,
409
+ } = await makeAndSignSponsoredRelayCall({
410
+ // this is the account that is to later execute the transaction and pay the additional relay fee.
411
+ // it will be the account that signs the message.
412
+ executingAccount: permitExecutorAccount!,
413
+ // the chain to call from (current chain)
414
+ originChainId: chainId,
415
+ // the chain that the call will be executed on
416
+ toChainId: destinationChainId,
417
+ // the tx to call on the other chain
418
+ tx: {
419
+ to: destinationContractAddress,
420
+ value: mintFeeOnOtherChain,
421
+ data: mintCall,
422
+ },
423
+ walletClient,
424
+ });
425
+
426
+ // build permit to transfer mints to the mintsEthUnwrapperAndCaller,
427
+ // and call the relay with the unwrapped value, and gets the data
428
+ // to be signed. This would be built on the client-side
429
+ const { typedData: transferTypeData, permit: transferPermit } =
430
+ unwrapAndForwardEthPermitAndTypedDataDefinition({
431
+ // mints will be transferred from this account
432
+ from: collectorAccount!,
433
+ chainId: chainId,
434
+ // random nonce
435
+ nonce: randomNonce(),
436
+ // deadling for signature
437
+ deadline: (await publicClient.getBlock()).timestamp + 100n,
438
+ // token ids to unwrap and burn - must be eth based token ids
439
+ tokenIds: [mintsTokenId],
440
+ // quantities to unwrap and burn
441
+ quantities: [quantityToMint],
442
+ // we already have the data to call the external contract
443
+ safeTransferData,
444
+ });
445
+
446
+ // have the collector sign the permit
447
+ const permitSignature =
448
+ await walletClient.signTypedData(transferTypeData);
449
+
450
+ // this call would happen on the server after the collector signs a message.
451
+ // the server would be passed the permit, permit signature, and
452
+ // sponsored call signature created above, then validate the sponsored call signature.
453
+ await validateAndExecuteSponsoredRelayCall({
454
+ permit: transferPermit,
455
+ permitSignature,
456
+ sponsoredCallSignature: sponsoredRelayCallSignature,
457
+ additionalValueToSend,
458
+ deadline,
459
+ chainId,
460
+ executingAccount: permitExecutorAccount!,
461
+ walletClient,
462
+ publicClient,
463
+ });
464
+ },
465
+ 10_000,
466
+ );
467
+ });
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  iUnwrapAndForwardActionABI,
3
- sparksEthUnwrapperAndCallerAddress,
3
+ mintsEthUnwrapperAndCallerAddress,
4
4
  zoraMints1155Config,
5
5
  } from "@zoralabs/protocol-deployments";
6
6
  import { Account, Address, Hex, encodeFunctionData } from "viem";
@@ -78,6 +78,6 @@ export const unwrapAndForwardEthPermitAndTypedDataDefinition = ({
78
78
  quantities,
79
79
  safeTransferData:
80
80
  safeTransferData || makeCallWithEthSafeTransferData(callWithEth),
81
- to: sparksEthUnwrapperAndCallerAddress[chainId],
81
+ to: mintsEthUnwrapperAndCallerAddress[chainId],
82
82
  nonce,
83
83
  });
@@ -0,0 +1,105 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ MintAccountBalance,
4
+ selectMintsToCollectWithFromQueryResult,
5
+ sumBalances,
6
+ } from "./mints-queries";
7
+
8
+ describe("MINTs queries", () => {
9
+ describe("selectMintsToCollectWithFromQueryResult", () => {
10
+ it("should return the optimum tokenIds and quantities to collect", async () => {
11
+ // account has 3 of token 1, 4 of token 2, 10 of token 3
12
+ // token 1 price is 2, token 2 price is 1, token 3 price is 3
13
+ // we want to collect 10 tokens
14
+ // we should return token 2 with 4 tokens, token 1 with 3 tokens, and token 3 with 3 tokens
15
+ const mintTokenBalances: MintAccountBalance[] = [
16
+ {
17
+ mintToken: {
18
+ id: "1",
19
+ pricePerToken: "2",
20
+ },
21
+ balance: "3",
22
+ },
23
+ {
24
+ mintToken: {
25
+ id: "2",
26
+ pricePerToken: "1",
27
+ },
28
+ balance: "4",
29
+ },
30
+ {
31
+ mintToken: {
32
+ id: "3",
33
+ pricePerToken: "3",
34
+ },
35
+ balance: "10",
36
+ },
37
+ ];
38
+
39
+ const result = selectMintsToCollectWithFromQueryResult(
40
+ mintTokenBalances,
41
+ 10n,
42
+ );
43
+
44
+ const expectedResult = {
45
+ tokenIds: [2n, 1n, 3n],
46
+ quantities: [4n, 3n, 3n],
47
+ };
48
+
49
+ expect(result).toEqual(expectedResult);
50
+ });
51
+
52
+ it("should throw an error if not enough tokens to collect with", () => {
53
+ const mintTokenBalances: MintAccountBalance[] = [
54
+ {
55
+ mintToken: {
56
+ id: "1",
57
+ pricePerToken: "2",
58
+ },
59
+ balance: "3",
60
+ },
61
+ {
62
+ mintToken: {
63
+ id: "2",
64
+ pricePerToken: "1",
65
+ },
66
+ balance: "4",
67
+ },
68
+ ];
69
+ const quantityToCollect = 8n;
70
+
71
+ expect(() => {
72
+ selectMintsToCollectWithFromQueryResult(
73
+ mintTokenBalances,
74
+ quantityToCollect,
75
+ );
76
+ }).toThrowError("Not enough MINTs to collect with");
77
+ });
78
+ });
79
+
80
+ describe("sumBalances", () => {
81
+ it("should return the sum of the balances", async () => {
82
+ // account has 3 of token 1, 4 of token 2, 10 of token 3
83
+ // token 1 price is 2, token 2 price is 1, token 3 price is 3
84
+ // we want to collect 10 tokens
85
+ // we should return token 2 with 4 tokens, token 1 with 3 tokens, and token 3 with 3 tokens
86
+ const mintTokenBalances: Pick<MintAccountBalance, "balance">[] = [
87
+ {
88
+ balance: "3",
89
+ },
90
+ {
91
+ balance: "4",
92
+ },
93
+ {
94
+ balance: "10",
95
+ },
96
+ ];
97
+
98
+ const result = sumBalances(mintTokenBalances);
99
+
100
+ const expectedResult = 3n + 4n + 10n;
101
+
102
+ expect(result).toEqual(expectedResult);
103
+ });
104
+ });
105
+ });
@@ -7,12 +7,11 @@ import {
7
7
  WalletClient,
8
8
  recoverTypedDataAddress,
9
9
  } from "viem";
10
- import axios from "axios";
11
10
  import { paths, TransactionStepItem } from "@reservoir0x/relay-sdk";
12
11
  import { PermitSafeTransferBatch } from "./mints-contracts";
13
12
  import {
14
- sparksEthUnwrapperAndCallerABI,
15
- sparksEthUnwrapperAndCallerAddress,
13
+ mintsEthUnwrapperAndCallerABI,
14
+ mintsEthUnwrapperAndCallerAddress,
16
15
  } from "@zoralabs/protocol-deployments";
17
16
  import { makeCallWithEthSafeTransferData } from "./mints-eth-unwrapper-and-caller";
18
17
 
@@ -32,8 +31,18 @@ const postToRelay = async ({
32
31
  data,
33
32
  };
34
33
 
35
- return (await axios.post(request.url, request.data))
36
- .data as RelayCallResponse;
34
+ const response = await fetch(request.url, {
35
+ method: "POST",
36
+ body: JSON.stringify(request.data),
37
+ headers: { "content-type": "application/json" },
38
+ });
39
+
40
+ if (response.ok) {
41
+ const responseJson = await response.json();
42
+ return responseJson as RelayCallResponse;
43
+ } else {
44
+ throw new Error("Bad response from relay");
45
+ }
37
46
  };
38
47
 
39
48
  export const getRelayCall = async ({
@@ -103,7 +112,7 @@ export const makeAndSignSponsoredRelayCall = async ({
103
112
  walletClient,
104
113
  }: {
105
114
  // the chain to call from (current chain)
106
- originChainId: keyof typeof sparksEthUnwrapperAndCallerAddress;
115
+ originChainId: keyof typeof mintsEthUnwrapperAndCallerAddress;
107
116
  // the chain that the call will be executed on
108
117
  toChainId: number;
109
118
  // the tx to call on the other chain:
@@ -120,7 +129,7 @@ export const makeAndSignSponsoredRelayCall = async ({
120
129
  originChainId,
121
130
  toChainId,
122
131
  tx,
123
- depositingAccount: sparksEthUnwrapperAndCallerAddress[originChainId],
132
+ depositingAccount: mintsEthUnwrapperAndCallerAddress[originChainId],
124
133
  });
125
134
 
126
135
  // build call to forward the relay call to the other chain that will be
@@ -173,7 +182,7 @@ export const validateSponsoredRelayCall = async ({
173
182
  additionalValueToSend: bigint;
174
183
  deadline: bigint;
175
184
  executingAccount: Address;
176
- chainId: keyof typeof sparksEthUnwrapperAndCallerAddress;
185
+ chainId: keyof typeof mintsEthUnwrapperAndCallerAddress;
177
186
  signature: Hex;
178
187
  }) => {
179
188
  const typedData = permitWithAdditionalValueTypedDataDefinition({
@@ -215,7 +224,7 @@ export const validateAndExecuteSponsoredRelayCall = async ({
215
224
  deadline: bigint;
216
225
  // account that is to execute the call, and must have signed the sponsored call
217
226
  executingAccount: Address;
218
- chainId: keyof typeof sparksEthUnwrapperAndCallerAddress;
227
+ chainId: keyof typeof mintsEthUnwrapperAndCallerAddress;
219
228
  // signature of the sponsored call
220
229
  sponsoredCallSignature: Hex;
221
230
  publicClient: PublicClient;
@@ -241,8 +250,8 @@ export const validateAndExecuteSponsoredRelayCall = async ({
241
250
  // value of the mints and sent to the other chain.
242
251
  // any remaining value from the unwrapped MINTs is refunded to the original caller.
243
252
  const simulated = await publicClient.simulateContract({
244
- abi: sparksEthUnwrapperAndCallerABI,
245
- address: sparksEthUnwrapperAndCallerAddress[chainId],
253
+ abi: mintsEthUnwrapperAndCallerABI,
254
+ address: mintsEthUnwrapperAndCallerAddress[chainId],
246
255
  functionName: "permitWithAdditionalValue",
247
256
  args: [permit, permitSignature],
248
257
  account: executingAccount,
@@ -278,7 +287,7 @@ function permitWithAdditionalValueTypedDataDefinition({
278
287
  safeTransferData: Hex;
279
288
  additionalValueToSend: bigint;
280
289
  deadline: bigint;
281
- chainId: keyof typeof sparksEthUnwrapperAndCallerAddress;
290
+ chainId: keyof typeof mintsEthUnwrapperAndCallerAddress;
282
291
  }) {
283
292
  return makeTypeData({
284
293
  primaryType: "PermitWithAdditionalValue",
@@ -307,7 +316,7 @@ function permitWithAdditionalValueTypedDataDefinition({
307
316
  chainId,
308
317
  name: "Relay",
309
318
  version: "1",
310
- verifyingContract: sparksEthUnwrapperAndCallerAddress[chainId],
319
+ verifyingContract: mintsEthUnwrapperAndCallerAddress[chainId],
311
320
  },
312
321
  });
313
322
  }