@zoralabs/protocol-sdk 0.11.4 → 0.11.6-COMMENTS.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +32 -0
- package/dist/create/mint-from-create.d.ts +2 -1
- package/dist/create/mint-from-create.d.ts.map +1 -1
- package/dist/create/minter-defaults.d.ts.map +1 -1
- package/dist/create/types.d.ts +1 -0
- package/dist/create/types.d.ts.map +1 -1
- package/dist/index.cjs +235 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +239 -58
- package/dist/index.js.map +1 -1
- package/dist/mint/mint-client.d.ts +3 -1
- package/dist/mint/mint-client.d.ts.map +1 -1
- package/dist/mint/mint-queries.d.ts +5 -3
- package/dist/mint/mint-queries.d.ts.map +1 -1
- package/dist/mint/mint-transactions.d.ts +4 -2
- package/dist/mint/mint-transactions.d.ts.map +1 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/secondary/secondary-client.d.ts +4 -3
- package/dist/secondary/secondary-client.d.ts.map +1 -1
- package/dist/secondary/types.d.ts +7 -0
- package/dist/secondary/types.d.ts.map +1 -1
- package/dist/secondary/utils.d.ts.map +1 -1
- package/dist/test-utils.d.ts +3 -1
- package/dist/test-utils.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/comments/comments.test.ts +342 -0
- package/src/create/1155-create-helper.test.ts +77 -14
- package/src/create/1155-create-helper.ts +2 -0
- package/src/create/mint-from-create.ts +3 -0
- package/src/create/minter-defaults.ts +22 -8
- package/src/create/types.ts +5 -3
- package/src/mint/mint-client.test.ts +67 -30
- package/src/mint/mint-client.ts +10 -1
- package/src/mint/mint-queries.ts +16 -5
- package/src/mint/mint-transactions.ts +80 -16
- package/src/sdk.ts +1 -0
- package/src/secondary/secondary-client.test.ts +149 -25
- package/src/secondary/secondary-client.ts +138 -7
- package/src/secondary/types.ts +19 -4
- package/src/secondary/utils.ts +30 -10
- package/src/sparks/sparks-sponsored-sparks-spender.test.ts +1 -1
- package/src/test-utils.ts +12 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, vi } from "vitest";
|
|
2
|
-
import { parseEther } from "viem";
|
|
2
|
+
import { parseEther, Address, parseEventLogs } from "viem";
|
|
3
3
|
import { zoraSepolia } from "viem/chains";
|
|
4
4
|
import {
|
|
5
5
|
forkUrls,
|
|
@@ -7,8 +7,12 @@ import {
|
|
|
7
7
|
simulateAndWriteContractWithRetries,
|
|
8
8
|
} from "src/anvil";
|
|
9
9
|
import { createCollectorClient } from "src/sdk";
|
|
10
|
-
import {
|
|
11
|
-
|
|
10
|
+
import {
|
|
11
|
+
zoraCreator1155ImplABI,
|
|
12
|
+
commentsABI,
|
|
13
|
+
callerAndCommenterABI,
|
|
14
|
+
} from "@zoralabs/protocol-deployments";
|
|
15
|
+
import { SubgraphMintGetter } from "src/mint/subgraph-mint-getter";
|
|
12
16
|
import { ERROR_SECONDARY_NOT_STARTED } from "./secondary-client";
|
|
13
17
|
import { ISubgraphQuerier } from "src/apis/subgraph-querier";
|
|
14
18
|
import { mockTimedSaleStrategyTokenQueryResult } from "src/fixtures/mint-query-results";
|
|
@@ -17,7 +21,7 @@ import { advanceToSaleAndAndLaunchMarket } from "src/fixtures/secondary";
|
|
|
17
21
|
|
|
18
22
|
describe("secondary", () => {
|
|
19
23
|
makeAnvilTest({
|
|
20
|
-
forkBlockNumber:
|
|
24
|
+
forkBlockNumber: 16072399,
|
|
21
25
|
forkUrl: forkUrls.zoraSepolia,
|
|
22
26
|
anvilChainId: zoraSepolia.id,
|
|
23
27
|
})(
|
|
@@ -25,16 +29,11 @@ describe("secondary", () => {
|
|
|
25
29
|
async ({
|
|
26
30
|
viemClients: { publicClient, chain, walletClient, testClient },
|
|
27
31
|
}) => {
|
|
28
|
-
const creatorAccount = (await walletClient.getAddresses()!)[0]!;
|
|
29
32
|
const collectorAccount = (await walletClient.getAddresses()!)[1]!;
|
|
30
33
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
creatorAccount,
|
|
35
|
-
walletClient,
|
|
36
|
-
});
|
|
37
|
-
|
|
34
|
+
const contractAddress: Address =
|
|
35
|
+
"0xd42557f24034b53e7340a40bb5813ef9ba88f2b4";
|
|
36
|
+
const newTokenId = 4n;
|
|
38
37
|
await testClient.setBalance({
|
|
39
38
|
address: collectorAccount,
|
|
40
39
|
value: parseEther("100"),
|
|
@@ -50,7 +49,10 @@ describe("secondary", () => {
|
|
|
50
49
|
tokenId: newTokenId,
|
|
51
50
|
});
|
|
52
51
|
|
|
53
|
-
expect(secondaryInfo
|
|
52
|
+
expect(secondaryInfo).toBeDefined();
|
|
53
|
+
|
|
54
|
+
expect(secondaryInfo!.minimumMintsForCountdown).toBe(1111n);
|
|
55
|
+
expect(secondaryInfo!.secondaryActivated).toBe(false);
|
|
54
56
|
|
|
55
57
|
const buyResult = await collectorClient.buy1155OnSecondary({
|
|
56
58
|
account: collectorAccount,
|
|
@@ -65,7 +67,7 @@ describe("secondary", () => {
|
|
|
65
67
|
);
|
|
66
68
|
|
|
67
69
|
makeAnvilTest({
|
|
68
|
-
forkBlockNumber:
|
|
70
|
+
forkBlockNumber: 16072399,
|
|
69
71
|
forkUrl: forkUrls.zoraSepolia,
|
|
70
72
|
anvilChainId: zoraSepolia.id,
|
|
71
73
|
})(
|
|
@@ -73,16 +75,12 @@ describe("secondary", () => {
|
|
|
73
75
|
async ({
|
|
74
76
|
viemClients: { publicClient, chain, walletClient, testClient },
|
|
75
77
|
}) => {
|
|
76
|
-
const creatorAccount = (await walletClient.getAddresses()!)[0]!;
|
|
77
78
|
const collectorAccount = (await walletClient.getAddresses()!)[1]!;
|
|
78
79
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
creatorAccount,
|
|
84
|
-
walletClient,
|
|
85
|
-
});
|
|
80
|
+
const mintGetter = new SubgraphMintGetter(chain.id);
|
|
81
|
+
const contractAddress: Address =
|
|
82
|
+
"0xd42557f24034b53e7340a40bb5813ef9ba88f2b4";
|
|
83
|
+
const newTokenId = 4n;
|
|
86
84
|
|
|
87
85
|
await testClient.setBalance({
|
|
88
86
|
address: collectorAccount,
|
|
@@ -109,13 +107,25 @@ describe("secondary", () => {
|
|
|
109
107
|
mintGetter,
|
|
110
108
|
});
|
|
111
109
|
|
|
110
|
+
const secondaryInfo = await collectorClient.getSecondaryInfo({
|
|
111
|
+
contract: contractAddress,
|
|
112
|
+
tokenId: newTokenId,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(secondaryInfo).toBeDefined();
|
|
116
|
+
expect(secondaryInfo!.mintCount).toBeGreaterThan(0n);
|
|
117
|
+
|
|
112
118
|
// mint 1 less than expected minimum market.
|
|
113
119
|
// make sure that there is no sale end
|
|
120
|
+
const quantityToMintFirst =
|
|
121
|
+
secondaryInfo!.minimumMintsForCountdown! -
|
|
122
|
+
secondaryInfo!.mintCount -
|
|
123
|
+
1n;
|
|
124
|
+
|
|
114
125
|
const { parameters: collectParameters } = await collectorClient.mint({
|
|
115
126
|
minterAccount: collectorAccount,
|
|
116
127
|
mintType: "1155",
|
|
117
|
-
|
|
118
|
-
quantityToMint: 1111n - 1n,
|
|
128
|
+
quantityToMint: quantityToMintFirst,
|
|
119
129
|
tokenId: newTokenId,
|
|
120
130
|
tokenContract: contractAddress,
|
|
121
131
|
});
|
|
@@ -245,8 +255,122 @@ describe("secondary", () => {
|
|
|
245
255
|
args: [collectorAccount, newTokenId],
|
|
246
256
|
});
|
|
247
257
|
|
|
248
|
-
expect(balance).toBe(
|
|
258
|
+
expect(balance).toBe(
|
|
259
|
+
quantityToMintFirst + 1n + quantityToBuy - quantityToSell,
|
|
260
|
+
);
|
|
249
261
|
},
|
|
250
262
|
30_000,
|
|
251
263
|
);
|
|
264
|
+
|
|
265
|
+
makeAnvilTest({
|
|
266
|
+
forkBlockNumber: 16123365,
|
|
267
|
+
forkUrl: forkUrls.zoraSepolia,
|
|
268
|
+
anvilChainId: zoraSepolia.id,
|
|
269
|
+
})(
|
|
270
|
+
"it can buy on secondary with a comment",
|
|
271
|
+
async ({
|
|
272
|
+
viemClients: { publicClient, chain, walletClient, testClient },
|
|
273
|
+
}) => {
|
|
274
|
+
const collectorAccount = (await walletClient.getAddresses()!)[1]!;
|
|
275
|
+
|
|
276
|
+
const mintGetter = new SubgraphMintGetter(chain.id);
|
|
277
|
+
const contractAddress: Address =
|
|
278
|
+
"0xd42557f24034b53e7340a40bb5813ef9ba88f2b4";
|
|
279
|
+
const newTokenId = 4n;
|
|
280
|
+
|
|
281
|
+
await testClient.setBalance({
|
|
282
|
+
address: collectorAccount,
|
|
283
|
+
value: parseEther("100"),
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
mintGetter.subgraphQuerier.query = vi
|
|
287
|
+
.fn<ISubgraphQuerier["query"]>()
|
|
288
|
+
.mockResolvedValue({
|
|
289
|
+
zoraCreateToken: mockTimedSaleStrategyTokenQueryResult({
|
|
290
|
+
chainId: chain.id,
|
|
291
|
+
tokenId: newTokenId,
|
|
292
|
+
contractAddress,
|
|
293
|
+
contractVersion:
|
|
294
|
+
new1155ContractVersion[
|
|
295
|
+
chain.id as keyof typeof new1155ContractVersion
|
|
296
|
+
],
|
|
297
|
+
}),
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const collectorClient = createCollectorClient({
|
|
301
|
+
chainId: chain.id,
|
|
302
|
+
publicClient,
|
|
303
|
+
mintGetter,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const secondaryInfo = await collectorClient.getSecondaryInfo({
|
|
307
|
+
contract: contractAddress,
|
|
308
|
+
tokenId: newTokenId,
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// mint enough to start the countdown
|
|
312
|
+
const quantityToMint =
|
|
313
|
+
secondaryInfo!.minimumMintsForCountdown! - secondaryInfo!.mintCount;
|
|
314
|
+
|
|
315
|
+
const { parameters: collectParameters } = await collectorClient.mint({
|
|
316
|
+
minterAccount: collectorAccount,
|
|
317
|
+
mintType: "1155",
|
|
318
|
+
quantityToMint: quantityToMint,
|
|
319
|
+
tokenId: newTokenId,
|
|
320
|
+
tokenContract: contractAddress,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
await simulateAndWriteContractWithRetries({
|
|
324
|
+
parameters: collectParameters,
|
|
325
|
+
walletClient,
|
|
326
|
+
publicClient,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
await advanceToSaleAndAndLaunchMarket({
|
|
330
|
+
contractAddress,
|
|
331
|
+
tokenId: newTokenId,
|
|
332
|
+
testClient,
|
|
333
|
+
publicClient,
|
|
334
|
+
walletClient,
|
|
335
|
+
collectorClient,
|
|
336
|
+
chainId: chain.id,
|
|
337
|
+
account: collectorAccount,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
const buyResult = await collectorClient.buy1155OnSecondary({
|
|
341
|
+
account: collectorAccount,
|
|
342
|
+
quantity: 5n,
|
|
343
|
+
contract: contractAddress,
|
|
344
|
+
tokenId: newTokenId,
|
|
345
|
+
comment: "test comment",
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
const receipt = await simulateAndWriteContractWithRetries({
|
|
349
|
+
parameters: buyResult.parameters!,
|
|
350
|
+
walletClient,
|
|
351
|
+
publicClient,
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const commentedEvent = parseEventLogs({
|
|
355
|
+
abi: commentsABI,
|
|
356
|
+
logs: receipt.logs,
|
|
357
|
+
eventName: "Commented",
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
expect(commentedEvent[0]).toBeDefined();
|
|
361
|
+
expect(commentedEvent[0]!.args.text).toBe("test comment");
|
|
362
|
+
|
|
363
|
+
const boughtAndCommentedEvent = parseEventLogs({
|
|
364
|
+
abi: callerAndCommenterABI,
|
|
365
|
+
logs: receipt.logs,
|
|
366
|
+
eventName: "SwappedOnSecondaryAndCommented",
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
expect(boughtAndCommentedEvent[0]).toBeDefined();
|
|
370
|
+
expect(boughtAndCommentedEvent[0]!.args.comment).toBe("test comment");
|
|
371
|
+
expect(boughtAndCommentedEvent[0]!.args.quantity).toBe(5n);
|
|
372
|
+
expect(boughtAndCommentedEvent[0]!.args.swapDirection).toBe(0);
|
|
373
|
+
},
|
|
374
|
+
20_000,
|
|
375
|
+
);
|
|
252
376
|
});
|
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
zoraCreator1155ImplABI,
|
|
5
5
|
safeTransferSwapAbiParameters,
|
|
6
6
|
secondarySwapABI,
|
|
7
|
+
callerAndCommenterABI,
|
|
8
|
+
callerAndCommenterAddress,
|
|
7
9
|
} from "@zoralabs/protocol-deployments";
|
|
8
10
|
import { makeContractParameters, PublicClient } from "src/utils";
|
|
9
11
|
import { getUniswapQuote } from "./uniswap/uniswapQuote";
|
|
@@ -15,6 +17,7 @@ import {
|
|
|
15
17
|
QuotePrice,
|
|
16
18
|
BuyWithSlippageInput,
|
|
17
19
|
SellWithSlippageInput,
|
|
20
|
+
SecondaryInfo,
|
|
18
21
|
} from "./types";
|
|
19
22
|
|
|
20
23
|
// uniswap's auto slippage for L2s is 0.5% -> 0.005
|
|
@@ -26,6 +29,8 @@ const ERROR_INSUFFICIENT_POOL_SUPPLY = "Insufficient pool supply";
|
|
|
26
29
|
const ERROR_SECONDARY_NOT_CONFIGURED =
|
|
27
30
|
"Secondary not configured for given contract and token";
|
|
28
31
|
export const ERROR_SECONDARY_NOT_STARTED = "Secondary market has not started";
|
|
32
|
+
export const ERROR_RECIPIENT_MISMATCH =
|
|
33
|
+
"Recipient must be the same as the caller if there is a comment";
|
|
29
34
|
|
|
30
35
|
// Helper function to create error objects
|
|
31
36
|
function makeError(errorMessage: string) {
|
|
@@ -45,6 +50,8 @@ type Call =
|
|
|
45
50
|
};
|
|
46
51
|
|
|
47
52
|
async function makeBuy({
|
|
53
|
+
contract,
|
|
54
|
+
tokenId,
|
|
48
55
|
erc20z,
|
|
49
56
|
poolBalance,
|
|
50
57
|
amount,
|
|
@@ -54,8 +61,11 @@ async function makeBuy({
|
|
|
54
61
|
chainId,
|
|
55
62
|
slippage,
|
|
56
63
|
publicClient,
|
|
64
|
+
comment,
|
|
57
65
|
}: {
|
|
58
66
|
erc20z: Address;
|
|
67
|
+
contract: Address;
|
|
68
|
+
tokenId: bigint;
|
|
59
69
|
poolBalance: { erc20z: bigint };
|
|
60
70
|
amount: bigint;
|
|
61
71
|
quantity: bigint;
|
|
@@ -63,27 +73,144 @@ async function makeBuy({
|
|
|
63
73
|
recipient?: Address;
|
|
64
74
|
chainId: number;
|
|
65
75
|
slippage: number;
|
|
76
|
+
comment: string | undefined;
|
|
66
77
|
publicClient: PublicClient;
|
|
67
78
|
}): Promise<Call> {
|
|
68
79
|
const costWithSlippage = calculateSlippageUp(amount, slippage);
|
|
80
|
+
const accountAddress = addressOrAccountAddress(account);
|
|
69
81
|
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
const validationResult = await validateBuyConditions({
|
|
83
|
+
poolBalance,
|
|
84
|
+
quantity,
|
|
85
|
+
costWithSlippage,
|
|
86
|
+
accountAddress,
|
|
87
|
+
publicClient,
|
|
88
|
+
});
|
|
72
89
|
|
|
73
|
-
|
|
90
|
+
if (validationResult.error) {
|
|
91
|
+
return makeError(validationResult.error);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (comment && comment !== "") {
|
|
95
|
+
return handleBuyWithComment({
|
|
96
|
+
accountAddress,
|
|
97
|
+
recipient,
|
|
98
|
+
chainId,
|
|
99
|
+
quantity,
|
|
100
|
+
contract,
|
|
101
|
+
tokenId,
|
|
102
|
+
costWithSlippage,
|
|
103
|
+
comment,
|
|
104
|
+
account,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return handleBuyWithoutComment({
|
|
109
|
+
erc20z,
|
|
110
|
+
quantity,
|
|
111
|
+
recipient,
|
|
112
|
+
accountAddress,
|
|
113
|
+
costWithSlippage,
|
|
114
|
+
chainId,
|
|
115
|
+
account,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
74
118
|
|
|
119
|
+
async function validateBuyConditions({
|
|
120
|
+
poolBalance,
|
|
121
|
+
quantity,
|
|
122
|
+
costWithSlippage,
|
|
123
|
+
accountAddress,
|
|
124
|
+
publicClient,
|
|
125
|
+
}: {
|
|
126
|
+
poolBalance: { erc20z: bigint };
|
|
127
|
+
quantity: bigint;
|
|
128
|
+
costWithSlippage: bigint;
|
|
129
|
+
accountAddress: Address;
|
|
130
|
+
publicClient: PublicClient;
|
|
131
|
+
}): Promise<{ error?: string }> {
|
|
132
|
+
const availableToBuy = poolBalance.erc20z / BigInt(1e18) - 1n;
|
|
75
133
|
const availableToSpend = await publicClient.getBalance({
|
|
76
134
|
address: accountAddress,
|
|
77
135
|
});
|
|
78
136
|
|
|
79
137
|
if (costWithSlippage > availableToSpend) {
|
|
80
|
-
return
|
|
138
|
+
return { error: ERROR_INSUFFICIENT_WALLET_FUNDS };
|
|
81
139
|
}
|
|
82
140
|
|
|
83
141
|
if (availableToBuy < BigInt(quantity)) {
|
|
84
|
-
return
|
|
142
|
+
return { error: ERROR_INSUFFICIENT_POOL_SUPPLY };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function handleBuyWithComment({
|
|
149
|
+
accountAddress,
|
|
150
|
+
recipient,
|
|
151
|
+
chainId,
|
|
152
|
+
quantity,
|
|
153
|
+
contract,
|
|
154
|
+
tokenId,
|
|
155
|
+
costWithSlippage,
|
|
156
|
+
comment,
|
|
157
|
+
account,
|
|
158
|
+
}: {
|
|
159
|
+
accountAddress: Address;
|
|
160
|
+
recipient?: Address;
|
|
161
|
+
chainId: number;
|
|
162
|
+
quantity: bigint;
|
|
163
|
+
contract: Address;
|
|
164
|
+
tokenId: bigint;
|
|
165
|
+
costWithSlippage: bigint;
|
|
166
|
+
comment: string;
|
|
167
|
+
account: Address | Account;
|
|
168
|
+
}): Call {
|
|
169
|
+
if (recipient && recipient !== accountAddress) {
|
|
170
|
+
return makeError(ERROR_RECIPIENT_MISMATCH);
|
|
85
171
|
}
|
|
86
172
|
|
|
173
|
+
return {
|
|
174
|
+
parameters: makeContractParameters({
|
|
175
|
+
abi: callerAndCommenterABI,
|
|
176
|
+
address:
|
|
177
|
+
callerAndCommenterAddress[
|
|
178
|
+
chainId as keyof typeof callerAndCommenterAddress
|
|
179
|
+
],
|
|
180
|
+
functionName: "buyOnSecondaryAndComment",
|
|
181
|
+
args: [
|
|
182
|
+
accountAddress,
|
|
183
|
+
quantity,
|
|
184
|
+
contract,
|
|
185
|
+
tokenId,
|
|
186
|
+
accountAddress,
|
|
187
|
+
costWithSlippage,
|
|
188
|
+
0n,
|
|
189
|
+
comment,
|
|
190
|
+
],
|
|
191
|
+
account,
|
|
192
|
+
value: costWithSlippage,
|
|
193
|
+
}),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function handleBuyWithoutComment({
|
|
198
|
+
erc20z,
|
|
199
|
+
quantity,
|
|
200
|
+
recipient,
|
|
201
|
+
accountAddress,
|
|
202
|
+
costWithSlippage,
|
|
203
|
+
chainId,
|
|
204
|
+
account,
|
|
205
|
+
}: {
|
|
206
|
+
erc20z: Address;
|
|
207
|
+
quantity: bigint;
|
|
208
|
+
recipient?: Address;
|
|
209
|
+
accountAddress: Address;
|
|
210
|
+
costWithSlippage: bigint;
|
|
211
|
+
chainId: number;
|
|
212
|
+
account: Address | Account;
|
|
213
|
+
}): Call {
|
|
87
214
|
return {
|
|
88
215
|
parameters: makeContractParameters({
|
|
89
216
|
abi: secondarySwapABI,
|
|
@@ -98,7 +225,7 @@ async function makeBuy({
|
|
|
98
225
|
costWithSlippage,
|
|
99
226
|
0n,
|
|
100
227
|
],
|
|
101
|
-
account
|
|
228
|
+
account,
|
|
102
229
|
value: costWithSlippage,
|
|
103
230
|
}),
|
|
104
231
|
};
|
|
@@ -124,6 +251,7 @@ export async function buyWithSlippage({
|
|
|
124
251
|
account,
|
|
125
252
|
slippage = UNISWAP_SLIPPAGE,
|
|
126
253
|
recipient,
|
|
254
|
+
comment,
|
|
127
255
|
}: BuyWithSlippageInput & {
|
|
128
256
|
chainId: number;
|
|
129
257
|
publicClient: PublicClient;
|
|
@@ -158,6 +286,8 @@ export async function buyWithSlippage({
|
|
|
158
286
|
|
|
159
287
|
const call = await makeBuy({
|
|
160
288
|
erc20z,
|
|
289
|
+
contract,
|
|
290
|
+
tokenId,
|
|
161
291
|
poolBalance,
|
|
162
292
|
amount,
|
|
163
293
|
quantity,
|
|
@@ -165,6 +295,7 @@ export async function buyWithSlippage({
|
|
|
165
295
|
recipient,
|
|
166
296
|
chainId,
|
|
167
297
|
slippage,
|
|
298
|
+
comment,
|
|
168
299
|
publicClient,
|
|
169
300
|
});
|
|
170
301
|
|
|
@@ -331,7 +462,7 @@ export class SecondaryClient {
|
|
|
331
462
|
}: {
|
|
332
463
|
contract: Address;
|
|
333
464
|
tokenId: bigint;
|
|
334
|
-
}) {
|
|
465
|
+
}): Promise<SecondaryInfo | undefined> {
|
|
335
466
|
return getSecondaryInfo({
|
|
336
467
|
contract,
|
|
337
468
|
tokenId,
|
package/src/secondary/types.ts
CHANGED
|
@@ -47,18 +47,33 @@ export type BuyWithSlippageInput = {
|
|
|
47
47
|
slippage?: number;
|
|
48
48
|
// Optional recipient address (if different from buyer/seller)
|
|
49
49
|
recipient?: Address;
|
|
50
|
+
// Optional comment to add to the swap
|
|
51
|
+
comment?: string;
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
// Same structure as BuyWithSlippageInput
|
|
53
55
|
export type SellWithSlippageInput = BuyWithSlippageInput;
|
|
54
56
|
|
|
57
|
+
// Base type for shared properties
|
|
55
58
|
export type SecondaryInfo = {
|
|
56
|
-
//
|
|
59
|
+
// Boolean if the secondary market has been launched
|
|
57
60
|
secondaryActivated: boolean;
|
|
58
|
-
//
|
|
61
|
+
// The Uniswap pool address
|
|
59
62
|
pool: Address;
|
|
60
|
-
//
|
|
63
|
+
// The ERC20z address
|
|
61
64
|
erc20z: Address;
|
|
62
|
-
//
|
|
65
|
+
// The ERC20Z name
|
|
66
|
+
name: string;
|
|
67
|
+
// The ERC20Z symbol
|
|
68
|
+
symbol: string;
|
|
69
|
+
// Earliest time in seconds a token can be minted
|
|
70
|
+
saleStart: bigint;
|
|
71
|
+
// Latest time in seconds a token can be minted. Gets set after the market countdown has started.
|
|
63
72
|
saleEnd?: bigint;
|
|
73
|
+
// The amount of time after the `minimumMarketEth` is reached until the secondary market can be launched, in seconds.
|
|
74
|
+
marketCountdown?: bigint;
|
|
75
|
+
// minimum quantity of tokens that must have been minted to launch the countdown.
|
|
76
|
+
minimumMintsForCountdown?: bigint;
|
|
77
|
+
// mints so far
|
|
78
|
+
mintCount: bigint;
|
|
64
79
|
};
|
package/src/secondary/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Address } from "viem";
|
|
1
|
+
import { Address, parseEther } from "viem";
|
|
2
2
|
import { PublicClient } from "src/utils";
|
|
3
3
|
import {
|
|
4
4
|
zoraTimedSaleStrategyABI,
|
|
@@ -16,15 +16,22 @@ export async function getSecondaryInfo({
|
|
|
16
16
|
publicClient: PublicClient;
|
|
17
17
|
chainId: number;
|
|
18
18
|
}): Promise<SecondaryInfo | undefined> {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
let result;
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
result = await publicClient.readContract({
|
|
23
|
+
abi: zoraTimedSaleStrategyABI,
|
|
24
|
+
address:
|
|
25
|
+
zoraTimedSaleStrategyAddress[
|
|
26
|
+
chainId as keyof typeof zoraTimedSaleStrategyAddress
|
|
27
|
+
],
|
|
28
|
+
functionName: "saleV2",
|
|
29
|
+
args: [contract, tokenId],
|
|
30
|
+
});
|
|
31
|
+
} catch (e) {
|
|
32
|
+
console.error(e);
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
28
35
|
|
|
29
36
|
// if there is no erc20zAddress, we can assume that secondary market has not been configured for this contract and token.
|
|
30
37
|
if (!result.erc20zAddress) {
|
|
@@ -36,5 +43,18 @@ export async function getSecondaryInfo({
|
|
|
36
43
|
pool: result.poolAddress,
|
|
37
44
|
secondaryActivated: result.secondaryActivated,
|
|
38
45
|
saleEnd: result.saleEnd === 0n ? undefined : result.saleEnd,
|
|
46
|
+
saleStart: result.saleStart,
|
|
47
|
+
name: result.name,
|
|
48
|
+
symbol: result.symbol,
|
|
49
|
+
marketCountdown:
|
|
50
|
+
result.marketCountdown === 0n ? undefined : result.marketCountdown,
|
|
51
|
+
minimumMintsForCountdown:
|
|
52
|
+
result.minimumMarketEth === 0n
|
|
53
|
+
? undefined
|
|
54
|
+
: result.minimumMarketEth / parseEther("0.0000111"),
|
|
55
|
+
mintCount:
|
|
56
|
+
(await publicClient.getBalance({
|
|
57
|
+
address: result.erc20zAddress,
|
|
58
|
+
})) / parseEther("0.0000111"),
|
|
39
59
|
};
|
|
40
60
|
}
|
|
@@ -19,7 +19,7 @@ import { zoraSparksManagerImplABI } from "@zoralabs/protocol-deployments";
|
|
|
19
19
|
const anvilTest = makeAnvilTest({
|
|
20
20
|
forkUrl: forkUrls.zoraMainnet,
|
|
21
21
|
anvilChainId: zora.id,
|
|
22
|
-
forkBlockNumber:
|
|
22
|
+
forkBlockNumber: 22029945,
|
|
23
23
|
});
|
|
24
24
|
describe("Sponsored Mints Spender with Relay", () => {
|
|
25
25
|
anvilTest(
|
package/src/test-utils.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
encodeAbiParameters,
|
|
10
10
|
parseAbiParameters,
|
|
11
11
|
} from "viem";
|
|
12
|
+
import { NewContractParams } from "./create/types";
|
|
12
13
|
import { expect } from "vitest";
|
|
13
14
|
|
|
14
15
|
export const waitForSuccess = async (hash: Hex, publicClient: PublicClient) => {
|
|
@@ -17,6 +18,8 @@ export const waitForSuccess = async (hash: Hex, publicClient: PublicClient) => {
|
|
|
17
18
|
});
|
|
18
19
|
|
|
19
20
|
expect(receipt.status).toBe("success");
|
|
21
|
+
|
|
22
|
+
return receipt;
|
|
20
23
|
};
|
|
21
24
|
|
|
22
25
|
export const getFixedPricedMinter = async ({
|
|
@@ -37,3 +40,12 @@ export const fixedPriceMinterMinterArguments = ({
|
|
|
37
40
|
}: {
|
|
38
41
|
mintRecipient: Address;
|
|
39
42
|
}) => encodeAbiParameters(parseAbiParameters("address"), [mintRecipient]);
|
|
43
|
+
|
|
44
|
+
const demoContractMetadataURI = "ipfs://DUMMY/contract.json";
|
|
45
|
+
|
|
46
|
+
export function randomNewContract(): NewContractParams {
|
|
47
|
+
return {
|
|
48
|
+
name: `testContract-${Math.round(Math.random() * 1_000_000)}`,
|
|
49
|
+
uri: demoContractMetadataURI,
|
|
50
|
+
};
|
|
51
|
+
}
|