@zoralabs/protocol-sdk 0.11.1 → 0.11.3-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.
@@ -6,15 +6,19 @@ import {
6
6
  IOnchainMintGetter,
7
7
  SaleType,
8
8
  OnchainMintable,
9
- OnchainSalesConfigAndTokenInfo,
10
9
  OnchainSalesStrategies,
10
+ GetMintableReturn,
11
11
  } from "./types";
12
12
  import {
13
13
  buildContractTokensQuery,
14
14
  buildNftTokenSalesQuery,
15
15
  buildPremintsOfContractQuery,
16
+ ERC20SaleStrategyResult,
17
+ FixedPriceSaleStrategyResult,
18
+ PresaleSalesStrategyResult,
16
19
  SalesStrategyResult,
17
20
  TokenQueryResult,
21
+ ZoraTimedMinterSaleStrategyResult,
18
22
  } from "./subgraph-queries";
19
23
  import { SubgraphGetter } from "src/apis/subgraph-getter";
20
24
 
@@ -24,90 +28,133 @@ export const getApiNetworkConfigForChain = (chainId: number): NetworkConfig => {
24
28
  }
25
29
  return networkConfigByChain[chainId]!;
26
30
  };
31
+ type ParsedSalesConfig = {
32
+ salesStrategy: OnchainSalesStrategies;
33
+ saleActive: boolean;
34
+ saleEnd: bigint | undefined;
35
+ secondaryMarketActive?: boolean;
36
+ };
27
37
 
28
- function parseSalesConfig(
29
- targetStrategy: SalesStrategyResult,
38
+ function parseFixedPriceSalesConfig(
39
+ fixedPrice: FixedPriceSaleStrategyResult["fixedPrice"],
30
40
  contractMintFee: bigint,
31
- ): OnchainSalesStrategies {
32
- if (targetStrategy.type === "FIXED_PRICE")
33
- return {
41
+ blockTime: bigint,
42
+ ): ParsedSalesConfig {
43
+ const saleEnd = BigInt(fixedPrice.saleEnd);
44
+ return {
45
+ salesStrategy: {
34
46
  saleType: "fixedPrice",
35
- ...targetStrategy.fixedPrice,
36
- maxTokensPerAddress: BigInt(
37
- targetStrategy.fixedPrice.maxTokensPerAddress,
38
- ),
39
- pricePerToken: BigInt(targetStrategy.fixedPrice.pricePerToken),
47
+ ...fixedPrice,
48
+ maxTokensPerAddress: BigInt(fixedPrice.maxTokensPerAddress),
49
+ pricePerToken: BigInt(fixedPrice.pricePerToken),
40
50
  mintFeePerQuantity: contractMintFee,
41
- };
51
+ },
52
+ saleEnd,
53
+ saleActive:
54
+ BigInt(fixedPrice.saleStart) <= blockTime && BigInt(saleEnd) > blockTime,
55
+ };
56
+ }
42
57
 
43
- if (targetStrategy.type === "ERC_20_MINTER") {
44
- return {
58
+ function parseERC20SalesConfig(
59
+ erc20Minter: ERC20SaleStrategyResult["erc20Minter"],
60
+ blockTime: bigint,
61
+ ): ParsedSalesConfig {
62
+ const saleEnd = BigInt(erc20Minter.saleEnd);
63
+ return {
64
+ salesStrategy: {
45
65
  saleType: "erc20",
46
- ...targetStrategy.erc20Minter,
47
- maxTokensPerAddress: BigInt(
48
- targetStrategy.erc20Minter.maxTokensPerAddress,
49
- ),
50
- pricePerToken: BigInt(targetStrategy.erc20Minter.pricePerToken),
66
+ ...erc20Minter,
67
+ maxTokensPerAddress: BigInt(erc20Minter.maxTokensPerAddress),
68
+ pricePerToken: BigInt(erc20Minter.pricePerToken),
51
69
  mintFeePerQuantity: 0n,
52
- };
53
- }
54
- if (targetStrategy.type === "PRESALE") {
55
- return {
70
+ },
71
+ saleEnd,
72
+ saleActive:
73
+ BigInt(erc20Minter.saleStart) <= blockTime && saleEnd > blockTime,
74
+ };
75
+ }
76
+
77
+ function parsePresaleSalesConfig(
78
+ presale: PresaleSalesStrategyResult["presale"],
79
+ contractMintFee: bigint,
80
+ blockTime: bigint,
81
+ ): ParsedSalesConfig {
82
+ const saleEnd = BigInt(presale.presaleEnd);
83
+ return {
84
+ salesStrategy: {
56
85
  saleType: "allowlist",
57
- address: targetStrategy.presale.address,
58
- merkleRoot: targetStrategy.presale.merkleRoot,
59
- saleStart: targetStrategy.presale.presaleStart,
60
- saleEnd: targetStrategy.presale.presaleEnd,
86
+ address: presale.address,
87
+ merkleRoot: presale.merkleRoot,
88
+ saleStart: presale.presaleStart,
89
+ saleEnd: presale.presaleEnd,
61
90
  mintFeePerQuantity: contractMintFee,
62
- };
63
- }
64
- if (targetStrategy.type === "ZORA_TIMED") {
65
- return {
91
+ },
92
+ saleEnd,
93
+ saleActive:
94
+ BigInt(presale.presaleStart) <= blockTime && saleEnd > blockTime,
95
+ };
96
+ }
97
+
98
+ function parseZoraTimedSalesConfig(
99
+ zoraTimedMinter: ZoraTimedMinterSaleStrategyResult["zoraTimedMinter"],
100
+ blockTime: bigint,
101
+ ): ParsedSalesConfig {
102
+ const saleEnd = BigInt(zoraTimedMinter.saleEnd);
103
+ const hasSaleEnd = saleEnd > 0n;
104
+ return {
105
+ salesStrategy: {
66
106
  saleType: "timed",
67
- address: targetStrategy.zoraTimedMinter.address,
68
- mintFee: BigInt(targetStrategy.zoraTimedMinter.mintFee),
69
- saleStart: targetStrategy.zoraTimedMinter.saleStart,
70
- saleEnd: targetStrategy.zoraTimedMinter.saleEnd,
71
- erc20Z: targetStrategy.zoraTimedMinter.erc20Z.id,
72
- pool: targetStrategy.zoraTimedMinter.erc20Z.pool,
73
- secondaryActivated: targetStrategy.zoraTimedMinter.secondaryActivated,
74
- mintFeePerQuantity: BigInt(targetStrategy.zoraTimedMinter.mintFee),
75
- marketCountdown: targetStrategy.zoraTimedMinter.marketCountdown
76
- ? BigInt(targetStrategy.zoraTimedMinter.marketCountdown)
107
+ address: zoraTimedMinter.address,
108
+ mintFee: BigInt(zoraTimedMinter.mintFee),
109
+ saleStart: zoraTimedMinter.saleStart,
110
+ saleEnd: zoraTimedMinter.saleEnd,
111
+ erc20Z: zoraTimedMinter.erc20Z.id,
112
+ pool: zoraTimedMinter.erc20Z.pool,
113
+ secondaryActivated: zoraTimedMinter.secondaryActivated,
114
+ mintFeePerQuantity: BigInt(zoraTimedMinter.mintFee),
115
+ marketCountdown: zoraTimedMinter.marketCountdown
116
+ ? BigInt(zoraTimedMinter.marketCountdown)
77
117
  : undefined,
78
- minimumMarketEth: targetStrategy.zoraTimedMinter.minimumMarketEth
79
- ? BigInt(targetStrategy.zoraTimedMinter.minimumMarketEth)
118
+ minimumMarketEth: zoraTimedMinter.minimumMarketEth
119
+ ? BigInt(zoraTimedMinter.minimumMarketEth)
80
120
  : undefined,
81
- };
82
- }
83
-
84
- throw new Error("Unknown saleType");
85
- }
86
-
87
- function getSaleEnd(a: SalesStrategyResult) {
88
- if (a.type === "FIXED_PRICE") return BigInt(a.fixedPrice.saleEnd);
89
- if (a.type === "ERC_20_MINTER") return BigInt(a.erc20Minter.saleEnd);
90
- if (a.type === "ZORA_TIMED") return BigInt(a.zoraTimedMinter.saleEnd);
91
- return BigInt(a.presale.presaleEnd);
121
+ },
122
+ saleEnd: hasSaleEnd ? saleEnd : undefined,
123
+ secondaryMarketActive: zoraTimedMinter.secondaryActivated,
124
+ saleActive:
125
+ BigInt(zoraTimedMinter.saleStart) <= blockTime &&
126
+ (hasSaleEnd ? saleEnd > blockTime : true),
127
+ };
92
128
  }
93
129
 
94
- function strategyIsStillValid(
95
- strategy: SalesStrategyResult,
130
+ function parseSalesConfig(
131
+ targetStrategy: SalesStrategyResult,
132
+ contractMintFee: bigint,
96
133
  blockTime: bigint,
97
- ): boolean {
98
- if (strategy.type === "FIXED_PRICE") {
99
- return BigInt(strategy.fixedPrice.saleEnd) > blockTime;
100
- }
101
- if (strategy.type === "ERC_20_MINTER") {
102
- return BigInt(strategy.erc20Minter.saleEnd) > blockTime;
103
- }
104
- if (strategy.type === "ZORA_TIMED") {
105
- return (
106
- BigInt(strategy.zoraTimedMinter.saleEnd) === 0n ||
107
- BigInt(strategy.zoraTimedMinter.saleEnd) > blockTime
108
- );
134
+ ): ParsedSalesConfig {
135
+ switch (targetStrategy.type) {
136
+ case "FIXED_PRICE":
137
+ return parseFixedPriceSalesConfig(
138
+ targetStrategy.fixedPrice,
139
+ contractMintFee,
140
+ blockTime,
141
+ );
142
+ case "ERC_20_MINTER":
143
+ return parseERC20SalesConfig(targetStrategy.erc20Minter, blockTime);
144
+ case "PRESALE":
145
+ return parsePresaleSalesConfig(
146
+ targetStrategy.presale,
147
+ contractMintFee,
148
+ blockTime,
149
+ );
150
+ case "ZORA_TIMED":
151
+ return parseZoraTimedSalesConfig(
152
+ targetStrategy.zoraTimedMinter,
153
+ blockTime,
154
+ );
155
+ default:
156
+ throw new Error("Unknown saleType");
109
157
  }
110
- return BigInt(strategy.presale.presaleEnd) > blockTime;
111
158
  }
112
159
 
113
160
  function getTargetStrategy({
@@ -115,39 +162,45 @@ function getTargetStrategy({
115
162
  preferredSaleType,
116
163
  token,
117
164
  blockTime,
165
+ contractMintFee,
118
166
  }: {
119
167
  tokenId?: GenericTokenIdTypes;
120
168
  preferredSaleType?: SaleType;
121
169
  token: TokenQueryResult;
122
170
  blockTime: bigint;
123
- }): SalesStrategyResult | undefined {
171
+ contractMintFee: bigint;
172
+ }): ParsedSalesConfig | undefined {
124
173
  const allStrategies =
125
174
  (typeof tokenId !== "undefined"
126
175
  ? token.salesStrategies
127
176
  : token.contract.salesStrategies) || [];
128
177
 
129
- const stillValidSalesStrategies = allStrategies.filter((strategy) =>
130
- strategyIsStillValid(strategy, blockTime),
178
+ const parsedStrategies = allStrategies.map((strategy) =>
179
+ parseSalesConfig(strategy, contractMintFee, blockTime),
180
+ );
181
+
182
+ const stillValidSalesStrategies = parsedStrategies.filter(
183
+ (strategy) => strategy.saleActive,
131
184
  );
132
185
 
133
186
  const saleStrategies = stillValidSalesStrategies.sort((a, b) =>
134
- getSaleEnd(a) > getSaleEnd(b) ? 1 : -1,
187
+ (a.saleEnd ?? 0n) > (b.saleEnd ?? 0n) ? 1 : -1,
135
188
  );
136
189
 
137
- let targetStrategy: SalesStrategyResult | undefined;
190
+ let targetStrategy: ParsedSalesConfig | undefined;
138
191
 
139
192
  if (!preferredSaleType) {
140
193
  return saleStrategies[0];
141
194
  } else {
142
- const mappedSaleType =
143
- preferredSaleType === "erc20" ? "ERC_20_MINTER" : "FIXED_PRICE";
144
195
  targetStrategy = saleStrategies.find(
145
- (strategy: SalesStrategyResult) => strategy.type === mappedSaleType,
196
+ ({ salesStrategy }) => salesStrategy.saleType === preferredSaleType,
146
197
  );
147
198
  if (!targetStrategy) {
148
199
  const targetStrategy = saleStrategies.find(
149
- (strategy: SalesStrategyResult) =>
150
- strategy.type === "FIXED_PRICE" || strategy.type === "ERC_20_MINTER",
200
+ ({ salesStrategy }) =>
201
+ salesStrategy.saleType === "timed" ||
202
+ salesStrategy.saleType === "fixedPrice" ||
203
+ salesStrategy.saleType === "erc20",
151
204
  );
152
205
  if (!targetStrategy) throw new Error("Cannot find valid sale strategy");
153
206
  return targetStrategy;
@@ -249,7 +302,7 @@ export class SubgraphMintGetter
249
302
  }
250
303
  }
251
304
 
252
- function getTargetStrategyAndMintFee({
305
+ function getTargetStrategyAndMintFeeAndSaleActive({
253
306
  token,
254
307
  tokenId,
255
308
  preferredSaleType,
@@ -267,13 +320,10 @@ function getTargetStrategyAndMintFee({
267
320
  preferredSaleType: preferredSaleType,
268
321
  token,
269
322
  blockTime,
323
+ contractMintFee: defaultMintFee,
270
324
  });
271
325
 
272
- if (!targetStrategy) return undefined;
273
-
274
- const salesConfig = parseSalesConfig(targetStrategy, defaultMintFee);
275
-
276
- return salesConfig;
326
+ return targetStrategy;
277
327
  }
278
328
 
279
329
  function parseTokenQueryResult({
@@ -288,8 +338,8 @@ function parseTokenQueryResult({
288
338
  preferredSaleType?: SaleType;
289
339
  defaultMintFee: bigint;
290
340
  blockTime: bigint;
291
- }): OnchainSalesConfigAndTokenInfo {
292
- const salesConfig = getTargetStrategyAndMintFee({
341
+ }): GetMintableReturn {
342
+ const salesStrategyAndMintInfo = getTargetStrategyAndMintFeeAndSaleActive({
293
343
  token,
294
344
  tokenId,
295
345
  preferredSaleType,
@@ -302,8 +352,14 @@ function parseTokenQueryResult({
302
352
  });
303
353
 
304
354
  return {
305
- ...tokenInfo,
306
- salesConfig,
355
+ salesConfigAndTokenInfo: {
356
+ ...tokenInfo,
357
+ salesConfig: salesStrategyAndMintInfo?.salesStrategy,
358
+ },
359
+ primaryMintActive: salesStrategyAndMintInfo?.saleActive ?? false,
360
+ primaryMintEnd: salesStrategyAndMintInfo?.saleEnd,
361
+ secondaryMarketActive:
362
+ salesStrategyAndMintInfo?.secondaryMarketActive ?? false,
307
363
  };
308
364
  }
309
365
 
@@ -311,7 +367,7 @@ function parseTokenInfo({
311
367
  token,
312
368
  }: {
313
369
  token: TokenQueryResult;
314
- }): OnchainMintable {
370
+ }): Omit<OnchainMintable, "primaryMintActive" | "primaryMintEnd"> {
315
371
  return {
316
372
  contract: {
317
373
  address: token.contract.address,
package/src/mint/types.ts CHANGED
@@ -226,17 +226,24 @@ export type SalesConfigAndTokenInfo =
226
226
  | OnchainSalesConfigAndTokenInfo
227
227
  | PremintMintable;
228
228
 
229
+ export type GetMintableReturn = {
230
+ salesConfigAndTokenInfo: OnchainSalesConfigAndTokenInfo;
231
+ secondaryMarketActive: boolean;
232
+ primaryMintActive: boolean;
233
+ primaryMintEnd?: bigint;
234
+ };
235
+
229
236
  export interface IOnchainMintGetter {
230
237
  getMintable(params: {
231
238
  tokenAddress: Address;
232
239
  tokenId?: GenericTokenIdTypes;
233
240
  preferredSaleType?: SaleType;
234
241
  blockTime: bigint;
235
- }): Promise<OnchainSalesConfigAndTokenInfo>;
242
+ }): Promise<GetMintableReturn>;
236
243
 
237
244
  getContractMintable(params: {
238
245
  tokenAddress: Address;
239
- }): Promise<OnchainSalesConfigAndTokenInfo[]>;
246
+ }): Promise<GetMintableReturn[]>;
240
247
 
241
248
  getContractPremintTokenIds(params: {
242
249
  tokenAddress: Address;
@@ -280,6 +287,17 @@ export type AsyncPrepareMint = (
280
287
  export type MintableReturn = {
281
288
  /** Token information */
282
289
  token: SalesConfigAndTokenInfo;
283
- /** Function that takes a quantity of items to mint and returns a prepared transaction and the costs to mint that quantity */
284
- prepareMint: PrepareMint;
285
- };
290
+ /** If the primary mint is active, the end time of the primary mint, if there is an end time */
291
+ primaryMintEnd?: bigint;
292
+ secondaryMarketActive: boolean;
293
+ } & (
294
+ | {
295
+ primaryMintActive: true;
296
+ /** Function that takes a quantity of items to mint and returns a prepared transaction and the costs to mint that quantity. If the primary mint is not active, it will be undefined. */
297
+ prepareMint: PrepareMint;
298
+ }
299
+ | {
300
+ primaryMintActive: false;
301
+ prepareMint?: undefined;
302
+ }
303
+ );
@@ -22,7 +22,7 @@ import { advanceToSaleAndAndLaunchMarket } from "src/secondary/secondary-client.
22
22
 
23
23
  describe("rewardsClient", () => {
24
24
  makeAnvilTest({
25
- forkBlockNumber: 13914833,
25
+ forkBlockNumber: 14653556,
26
26
  forkUrl: forkUrls.zoraSepolia,
27
27
  anvilChainId: zoraSepolia.id,
28
28
  })(
@@ -117,7 +117,7 @@ describe("rewardsClient", () => {
117
117
  30_000,
118
118
  );
119
119
  makeAnvilTest({
120
- forkBlockNumber: 13914833,
120
+ forkBlockNumber: 14653556,
121
121
  forkUrl: forkUrls.zoraSepolia,
122
122
  anvilChainId: zoraSepolia.id,
123
123
  })(
@@ -80,7 +80,7 @@ export async function advanceToSaleAndAndLaunchMarket({
80
80
 
81
81
  describe("secondary", () => {
82
82
  makeAnvilTest({
83
- forkBlockNumber: 13914833,
83
+ forkBlockNumber: 14653556,
84
84
  forkUrl: forkUrls.zoraSepolia,
85
85
  anvilChainId: zoraSepolia.id,
86
86
  })(
@@ -128,7 +128,7 @@ describe("secondary", () => {
128
128
  );
129
129
 
130
130
  makeAnvilTest({
131
- forkBlockNumber: 13914833,
131
+ forkBlockNumber: 14653556,
132
132
  forkUrl: forkUrls.zoraSepolia,
133
133
  anvilChainId: zoraSepolia.id,
134
134
  })(
@@ -199,6 +199,13 @@ describe("secondary", () => {
199
199
  account: collectorAccount,
200
200
  });
201
201
 
202
+ const balanceBefore = await publicClient.readContract({
203
+ abi: zoraCreator1155ImplABI,
204
+ address: contractAddress,
205
+ functionName: "balanceOf",
206
+ args: [collectorAccount, newTokenId],
207
+ });
208
+
202
209
  // now get the price ot buy on secondary
203
210
  const quantityToBuy = 1000n;
204
211
 
@@ -236,7 +243,7 @@ describe("secondary", () => {
236
243
  args: [collectorAccount, newTokenId],
237
244
  });
238
245
 
239
- expect(balance).toBe(quantityToBuy + quantityToMint);
246
+ expect(balance - balanceBefore).toBe(quantityToBuy);
240
247
 
241
248
  // now sell 10_000n tokens
242
249
  const quantityToSell = 10_000n;