@zoralabs/protocol-sdk 0.5.8-DEV.2 → 0.5.9
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.
- package/.turbo/turbo-build.log +15 -0
- package/CHANGELOG.md +7 -8
- package/dist/create/1155-create-helper.d.ts +2 -1
- package/dist/create/1155-create-helper.d.ts.map +1 -1
- package/dist/index.cjs +221 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +221 -51
- package/dist/index.js.map +1 -1
- package/dist/mints/mints-contracts.d.ts +2849 -74
- package/dist/mints/mints-contracts.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/create/1155-create-helper.test.ts +137 -0
- package/src/create/1155-create-helper.ts +3 -0
- package/src/mint/mint-client.test.ts +114 -0
- package/src/mints/mints-contracts.test.ts +719 -0
- package/src/mints/mints-contracts.ts +310 -63
- package/src/mints/mints-queries.test.ts +105 -0
- package/src/premint/premint-client.test.ts +239 -0
- package/src/premint/preminter.test.ts +619 -0
- package/test-integration/premint-client.test.ts +146 -0
- package/tsconfig.build.json +10 -0
- package/tsup.config.ts +12 -0
|
@@ -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
|
+
});
|