@zoralabs/protocol-sdk 0.3.2 → 0.3.3

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.
@@ -2,12 +2,14 @@ import {
2
2
  Address,
3
3
  Chain,
4
4
  PublicClient,
5
+ createPublicClient,
5
6
  encodeAbiParameters,
6
7
  parseAbi,
7
8
  parseAbiParameters,
8
9
  zeroAddress,
10
+ http,
9
11
  } from "viem";
10
- import { ClientBase } from "../apis/client-base";
12
+ import { IHttpClient } from "../apis/http-api-base";
11
13
  import { MintAPIClient, MintableGetTokenResponse } from "./mint-api-client";
12
14
  import { SimulateContractParameters } from "viem";
13
15
  import {
@@ -30,30 +32,31 @@ type MintArguments = {
30
32
  mintToAddress: Address;
31
33
  };
32
34
 
33
- type MintParameters = {
34
- mintArguments: MintArguments;
35
- publicClient: PublicClient;
36
- mintable: MintableGetTokenResponse;
37
- sender: Address;
38
- };
39
-
40
35
  const zora721Abi = parseAbi([
41
36
  "function mintWithRewards(address recipient, uint256 quantity, string calldata comment, address mintReferral) external payable",
42
37
  "function zoraFeeForAmount(uint256 amount) public view returns (address, uint256)",
43
38
  ] as const);
44
39
 
45
- class MintClient extends ClientBase {
46
- apiClient: typeof MintAPIClient;
47
-
48
- constructor(chain: Chain, apiClient?: typeof MintAPIClient) {
49
- super(chain);
40
+ class MintClient {
41
+ readonly apiClient: MintAPIClient;
42
+ readonly publicClient: PublicClient;
50
43
 
51
- if (!apiClient) {
52
- apiClient = MintAPIClient;
53
- }
54
- this.apiClient = apiClient;
44
+ constructor(
45
+ chain: Chain,
46
+ publicClient?: PublicClient,
47
+ httpClient?: IHttpClient,
48
+ ) {
49
+ this.apiClient = new MintAPIClient(chain.id, httpClient);
50
+ this.publicClient =
51
+ publicClient || createPublicClient({ chain, transport: http() });
55
52
  }
56
53
 
54
+ /**
55
+ * Gets mintable information for a given token
56
+ * @param param0.tokenContract The contract address of the token to mint.
57
+ * @param param0.tokenId The token id to mint.
58
+ * @returns
59
+ */
57
60
  async getMintable({
58
61
  tokenContract,
59
62
  tokenId,
@@ -61,168 +64,333 @@ class MintClient extends ClientBase {
61
64
  tokenContract: Address;
62
65
  tokenId?: bigint | number | string;
63
66
  }) {
64
- return this.apiClient.getMintable(
65
- {
66
- chain_name: this.network.zoraBackendChainName,
67
- collection_address: tokenContract,
68
- },
69
- { token_id: tokenId?.toString() },
70
- );
67
+ return await this.apiClient.getMintableForToken({
68
+ tokenContract,
69
+ tokenId: tokenId?.toString(),
70
+ });
71
71
  }
72
72
 
73
+ /**
74
+ * Returns the parameters needed to prepare a transaction mint a token.
75
+ * @param param0.minterAccount The account that will mint the token.
76
+ * @param param0.mintable The mintable token to mint.
77
+ * @param param0.mintArguments The arguments for the mint (mint recipient, comment, mint referral, quantity to mint)
78
+ * @returns
79
+ */
73
80
  async makePrepareMintTokenParams({
74
- publicClient,
75
- minterAccount,
76
- mintable,
77
- mintArguments,
81
+ ...rest
78
82
  }: {
79
- publicClient: PublicClient;
80
- mintable: MintableGetTokenResponse;
81
83
  minterAccount: Address;
84
+ mintable: MintableGetTokenResponse;
82
85
  mintArguments: MintArguments;
83
- }): Promise<{ simulateContractParameters: SimulateContractParameters }> {
84
- if (!mintable) {
85
- throw new MintError("No mintable found");
86
- }
86
+ }): Promise<SimulateContractParameters> {
87
+ return makePrepareMintTokenParams({
88
+ ...rest,
89
+ apiClient: this.apiClient,
90
+ publicClient: this.publicClient,
91
+ });
92
+ }
87
93
 
88
- if (!mintable.is_active) {
89
- throw new MintInactiveError("Minting token is inactive");
90
- }
94
+ /**
95
+ * Returns the mintFee, sale fee, and total cost of minting x quantities of a token.
96
+ * @param param0.mintable The mintable token to mint.
97
+ * @param param0.quantityToMint The quantity of tokens to mint.
98
+ * @returns
99
+ */
100
+ async getMintCosts({
101
+ mintable,
102
+ quantityToMint,
103
+ }: {
104
+ mintable: Mintable;
105
+ quantityToMint: number | bigint;
106
+ }): Promise<MintCosts> {
107
+ const mintContextType = validateMintableAndGetContextType(mintable);
91
108
 
92
- if (!mintable.mint_context) {
93
- throw new MintError("No minting context data from zora API");
109
+ if (mintContextType === "zora_create_1155") {
110
+ return await get1155MintCosts({
111
+ mintable,
112
+ publicClient: this.publicClient,
113
+ quantityToMint: BigInt(quantityToMint),
114
+ });
94
115
  }
95
-
96
- if (
97
- !["zora_create", "zora_create_1155"].includes(
98
- mintable.mint_context?.mint_context_type!,
99
- )
100
- ) {
101
- throw new MintError(
102
- `Mintable type ${mintable.mint_context.mint_context_type} is currently unsupported.`,
103
- );
116
+ if (mintContextType === "zora_create") {
117
+ return await get721MintCosts({
118
+ mintable,
119
+ publicClient: this.publicClient,
120
+ quantityToMint: BigInt(quantityToMint),
121
+ });
104
122
  }
105
123
 
106
- const thisPublicClient = this.getPublicClient(publicClient);
107
-
108
- if (mintable.mint_context.mint_context_type === "zora_create_1155") {
109
- return {
110
- simulateContractParameters: await this.prepareMintZora1155({
111
- publicClient: thisPublicClient,
112
- mintArguments,
113
- sender: minterAccount,
114
- mintable,
115
- }),
116
- };
117
- }
118
- if (mintable.mint_context.mint_context_type === "zora_create") {
119
- return {
120
- simulateContractParameters: await this.prepareMintZora721({
121
- publicClient: thisPublicClient,
122
- mintArguments,
123
- sender: minterAccount,
124
- mintable,
125
- }),
126
- };
127
- }
124
+ throw new MintError(
125
+ `Mintable type ${mintContextType} is currently unsupported.`,
126
+ );
127
+ }
128
+ }
128
129
 
129
- throw new Error("Mintable type not found or recognized.");
130
+ /**
131
+ * Creates a new MintClient.
132
+ * @param param0.chain The chain to use for the mint client.
133
+ * @param param0.publicClient Optional viem public client
134
+ * @param param0.httpClient Optional http client to override post, get, and retry methods
135
+ * @returns
136
+ */
137
+ export function createMintClient({
138
+ chain,
139
+ publicClient,
140
+ httpClient,
141
+ }: {
142
+ chain: Chain;
143
+ publicClient?: PublicClient;
144
+ httpClient?: IHttpClient;
145
+ }) {
146
+ return new MintClient(chain, publicClient, httpClient);
147
+ }
148
+
149
+ export type TMintClient = ReturnType<typeof createMintClient>;
150
+
151
+ function validateMintableAndGetContextType(
152
+ mintable: MintableGetTokenResponse | undefined,
153
+ ) {
154
+ if (!mintable) {
155
+ throw new MintError("No mintable found");
130
156
  }
131
157
 
132
- private async prepareMintZora1155({
133
- mintable,
134
- sender,
135
- publicClient,
136
- mintArguments,
137
- }: MintParameters) {
138
- const mintQuantity = BigInt(mintArguments.quantityToMint);
158
+ if (!mintable.is_active) {
159
+ throw new MintInactiveError("Minting token is inactive");
160
+ }
139
161
 
140
- const address = mintable.collection.address as Address;
162
+ if (!mintable.mint_context) {
163
+ throw new MintError("No minting context data from zora API");
164
+ }
141
165
 
142
- const mintFee = await publicClient.readContract({
143
- abi: zoraCreator1155ImplABI,
144
- functionName: "mintFee",
145
- address,
166
+ if (
167
+ !["zora_create", "zora_create_1155"].includes(
168
+ mintable.mint_context?.mint_context_type!,
169
+ )
170
+ ) {
171
+ throw new MintError(
172
+ `Mintable type ${mintable.mint_context.mint_context_type} is currently unsupported.`,
173
+ );
174
+ }
175
+
176
+ return mintable.mint_context.mint_context_type;
177
+ }
178
+
179
+ async function makePrepareMintTokenParams({
180
+ publicClient,
181
+ mintable,
182
+ apiClient,
183
+ ...rest
184
+ }: {
185
+ publicClient: PublicClient;
186
+ minterAccount: Address;
187
+ mintable: MintableGetTokenResponse;
188
+ mintArguments: MintArguments;
189
+ apiClient: MintAPIClient;
190
+ }): Promise<SimulateContractParameters> {
191
+ const mintContextType = validateMintableAndGetContextType(mintable);
192
+
193
+ const thisPublicClient = publicClient;
194
+
195
+ if (mintContextType === "zora_create_1155") {
196
+ return makePrepareMint1155TokenParams({
197
+ apiClient,
198
+ publicClient: thisPublicClient,
199
+ mintable,
200
+ mintContextType,
201
+ ...rest,
202
+ });
203
+ }
204
+ if (mintContextType === "zora_create") {
205
+ return makePrepareMint721TokenParams({
206
+ publicClient: thisPublicClient,
207
+ mintable,
208
+ mintContextType,
209
+ ...rest,
146
210
  });
211
+ }
147
212
 
148
- const tokenFixedPriceMinter = await this.apiClient.getSalesConfigFixedPrice(
149
- {
150
- contractAddress: mintable.contract_address,
151
- tokenId: mintable.token_id!,
152
- subgraphUrl: this.network.subgraphUrl,
153
- },
154
- );
213
+ throw new MintError(
214
+ `Mintable type ${mintContextType} is currently unsupported.`,
215
+ );
216
+ }
217
+
218
+ async function get721MintCosts({
219
+ mintable,
220
+ publicClient,
221
+ quantityToMint,
222
+ }: {
223
+ mintable: MintableGetTokenResponse;
224
+ publicClient: PublicClient;
225
+ quantityToMint: bigint;
226
+ }): Promise<MintCosts> {
227
+ const address = mintable.collection.address as Address;
155
228
 
156
- const result: SimulateContractParameters<
157
- typeof zoraCreator1155ImplABI,
158
- "mintWithRewards"
159
- > = {
160
- abi: zoraCreator1155ImplABI,
161
- functionName: "mintWithRewards",
162
- account: sender,
163
- value: (mintFee + BigInt(mintable.cost.native_price.raw)) * mintQuantity,
164
- address,
165
- /* args: minter, tokenId, quantity, minterArguments, mintReferral */
166
- args: [
167
- (tokenFixedPriceMinter ||
168
- zoraCreatorFixedPriceSaleStrategyAddress[999]) as Address,
169
- BigInt(mintable.token_id!),
170
- mintQuantity,
171
- encodeAbiParameters(parseAbiParameters("address, string"), [
172
- mintArguments.mintToAddress,
173
- mintArguments.mintComment || "",
174
- ]),
175
- mintArguments.mintReferral || zeroAddress,
176
- ],
177
- };
178
-
179
- return result;
229
+ const [_, mintFee] = await publicClient.readContract({
230
+ abi: zora721Abi,
231
+ address,
232
+ functionName: "zoraFeeForAmount",
233
+ args: [BigInt(quantityToMint)],
234
+ });
235
+
236
+ const tokenPurchaseCost =
237
+ BigInt(mintable.cost.native_price.raw) * quantityToMint;
238
+ return {
239
+ mintFee,
240
+ tokenPurchaseCost,
241
+ totalCost: mintFee + tokenPurchaseCost,
242
+ };
243
+ }
244
+
245
+ async function makePrepareMint721TokenParams({
246
+ publicClient,
247
+ minterAccount,
248
+ mintable,
249
+ mintContextType,
250
+ mintArguments,
251
+ }: {
252
+ publicClient: PublicClient;
253
+ mintable: MintableGetTokenResponse;
254
+ mintContextType: ReturnType<typeof validateMintableAndGetContextType>;
255
+ minterAccount: Address;
256
+ mintArguments: MintArguments;
257
+ }): Promise<SimulateContractParameters<typeof zora721Abi, "mintWithRewards">> {
258
+ if (mintContextType !== "zora_create") {
259
+ throw new Error("Minted token type must be for 1155");
180
260
  }
181
261
 
182
- private async prepareMintZora721({
183
- mintable,
262
+ const mintValue = (
263
+ await get721MintCosts({
264
+ mintable,
265
+ publicClient,
266
+ quantityToMint: BigInt(mintArguments.quantityToMint),
267
+ })
268
+ ).totalCost;
269
+
270
+ const result = {
271
+ abi: zora721Abi,
272
+ address: mintable.contract_address as Address,
273
+ account: minterAccount,
274
+ functionName: "mintWithRewards",
275
+ value: mintValue,
276
+ args: [
277
+ mintArguments.mintToAddress,
278
+ BigInt(mintArguments.quantityToMint),
279
+ mintArguments.mintComment || "",
280
+ mintArguments.mintReferral || zeroAddress,
281
+ ],
282
+ } satisfies SimulateContractParameters<typeof zora721Abi, "mintWithRewards">;
283
+
284
+ return result;
285
+ }
286
+
287
+ async function get1155MintFee({
288
+ collectionAddress,
289
+ publicClient,
290
+ }: {
291
+ collectionAddress: Address;
292
+ publicClient: PublicClient;
293
+ }) {
294
+ return await publicClient.readContract({
295
+ abi: zoraCreator1155ImplABI,
296
+ functionName: "mintFee",
297
+ address: collectionAddress,
298
+ });
299
+ }
300
+
301
+ export type MintCosts = {
302
+ mintFee: bigint;
303
+ tokenPurchaseCost: bigint;
304
+ totalCost: bigint;
305
+ };
306
+
307
+ export async function get1155MintCosts({
308
+ mintable,
309
+ publicClient,
310
+ quantityToMint,
311
+ }: {
312
+ mintable: MintableGetTokenResponse;
313
+ publicClient: PublicClient;
314
+ quantityToMint: bigint;
315
+ }): Promise<MintCosts> {
316
+ const address = mintable.collection.address as Address;
317
+
318
+ const mintFee = await get1155MintFee({
319
+ collectionAddress: address,
184
320
  publicClient,
185
- sender,
186
- mintArguments,
187
- }: MintParameters) {
188
- const [_, mintFee] = await publicClient.readContract({
189
- abi: zora721Abi,
190
- address: mintable.contract_address as Address,
191
- functionName: "zoraFeeForAmount",
192
- args: [BigInt(mintArguments.quantityToMint)],
193
- });
321
+ });
194
322
 
195
- const result: SimulateContractParameters<
196
- typeof zora721Abi,
197
- "mintWithRewards"
198
- > = {
199
- abi: zora721Abi,
200
- address: mintable.contract_address as Address,
201
- account: sender,
202
- functionName: "mintWithRewards",
203
- value:
204
- mintFee +
205
- BigInt(mintable.cost.native_price.raw) *
206
- BigInt(mintArguments.quantityToMint),
207
- /* args: mint recipient, quantity to mint, mint comment, mintReferral */
208
- args: [
209
- mintArguments.mintToAddress,
210
- BigInt(mintArguments.quantityToMint),
211
- mintArguments.mintComment || "",
212
- mintArguments.mintReferral || zeroAddress,
213
- ],
214
- };
323
+ const mintFeeForTokens = mintFee * quantityToMint;
324
+ const tokenPurchaseCost =
325
+ BigInt(mintable.cost.native_price.raw) * quantityToMint;
215
326
 
216
- return result;
217
- }
327
+ return {
328
+ mintFee: mintFeeForTokens,
329
+ tokenPurchaseCost,
330
+ totalCost: mintFeeForTokens + tokenPurchaseCost,
331
+ };
218
332
  }
219
333
 
220
- export function createMintClient({
221
- chain,
222
- mintAPIClient,
334
+ async function makePrepareMint1155TokenParams({
335
+ apiClient,
336
+ publicClient,
337
+ minterAccount,
338
+ mintable,
339
+ mintContextType,
340
+ mintArguments,
223
341
  }: {
224
- chain: Chain;
225
- mintAPIClient?: typeof MintAPIClient;
342
+ apiClient: Pick<MintAPIClient, "getSalesConfigFixedPrice">;
343
+ publicClient: PublicClient;
344
+ mintable: Mintable;
345
+ mintContextType: ReturnType<typeof validateMintableAndGetContextType>;
346
+ minterAccount: Address;
347
+ mintArguments: MintArguments;
226
348
  }) {
227
- return new MintClient(chain, mintAPIClient);
349
+ if (mintContextType !== "zora_create_1155") {
350
+ throw new Error("Minted token type must be for 1155");
351
+ }
352
+
353
+ const mintQuantity = BigInt(mintArguments.quantityToMint);
354
+
355
+ const address = mintable.collection.address as Address;
356
+
357
+ const mintValue = (
358
+ await get1155MintCosts({
359
+ mintable,
360
+ publicClient,
361
+ quantityToMint: mintQuantity,
362
+ })
363
+ ).totalCost;
364
+
365
+ const tokenFixedPriceMinter = await apiClient.getSalesConfigFixedPrice({
366
+ contractAddress: address,
367
+ tokenId: BigInt(mintable.token_id!),
368
+ });
369
+
370
+ const result = {
371
+ abi: zoraCreator1155ImplABI,
372
+ functionName: "mintWithRewards",
373
+ account: minterAccount,
374
+ value: mintValue,
375
+ address,
376
+ /* args: minter, tokenId, quantity, minterArguments, mintReferral */
377
+ args: [
378
+ (tokenFixedPriceMinter ||
379
+ zoraCreatorFixedPriceSaleStrategyAddress[999]) as Address,
380
+ BigInt(mintable.token_id!),
381
+ mintQuantity,
382
+ encodeAbiParameters(parseAbiParameters("address, string"), [
383
+ mintArguments.mintToAddress,
384
+ mintArguments.mintComment || "",
385
+ ]),
386
+ mintArguments.mintReferral || zeroAddress,
387
+ ],
388
+ } satisfies SimulateContractParameters<
389
+ typeof zoraCreator1155ImplABI,
390
+ "mintWithRewards"
391
+ >;
392
+
393
+ return result;
228
394
  }
395
+
396
+ export type Mintable = MintableGetTokenResponse;
@@ -1,6 +1,11 @@
1
- import { post, retries, get } from "../apis/http-api-base";
1
+ import {
2
+ IHttpClient,
3
+ httpClient as defaultHttpClient,
4
+ } from "../apis/http-api-base";
2
5
  import { components, paths } from "../apis/generated/premint-api-types";
3
6
  import { ZORA_API_BASE } from "../constants";
7
+ import { NetworkConfig } from "src/apis/chain-constants";
8
+ import { getApiNetworkConfigForChain } from "src/mint/mint-api-client";
4
9
 
5
10
  type SignaturePostType = paths["/signature"]["post"];
6
11
  type PremintSignatureRequestBody =
@@ -22,36 +27,85 @@ type PremintSignatureGetPathParameters =
22
27
  export type PremintSignatureGetResponse =
23
28
  SignaturePremintGetType["responses"][200]["content"]["application/json"];
24
29
 
30
+ export type PremintCollection = PremintSignatureGetResponse["collection"];
31
+
25
32
  export type BackendChainNames = components["schemas"]["ChainName"];
26
33
 
27
- const postSignature = async (
28
- data: PremintSignatureRequestBody,
29
- ): Promise<PremintSignatureResponse> =>
34
+ const postSignature = async ({
35
+ httpClient: { post, retries } = defaultHttpClient,
36
+ ...data
37
+ }: PremintSignatureRequestBody & {
38
+ httpClient?: Pick<IHttpClient, "retries" | "post">;
39
+ }): Promise<PremintSignatureResponse> =>
30
40
  retries(() =>
31
41
  post<PremintSignatureResponse>(`${ZORA_API_BASE}premint/signature`, data),
32
42
  );
33
43
 
34
- const getNextUID = async (
35
- path: PremintNextUIDGetPathParameters,
36
- ): Promise<PremintNextUIDGetResponse> =>
44
+ const getNextUID = async ({
45
+ chain_name,
46
+ collection_address,
47
+ httpClient: { retries, get } = defaultHttpClient,
48
+ }: PremintNextUIDGetPathParameters & {
49
+ httpClient?: Pick<IHttpClient, "retries" | "get">;
50
+ }): Promise<PremintNextUIDGetResponse> =>
37
51
  retries(() =>
38
52
  get<PremintNextUIDGetResponse>(
39
- `${ZORA_API_BASE}premint/signature/${path.chain_name}/${path.collection_address}/next_uid`,
53
+ `${ZORA_API_BASE}premint/signature/${chain_name}/${collection_address}/next_uid`,
40
54
  ),
41
55
  );
42
56
 
43
- const getSignature = async (
44
- path: PremintSignatureGetPathParameters,
45
- ): Promise<PremintSignatureGetResponse> =>
57
+ const getSignature = async ({
58
+ collection_address,
59
+ uid,
60
+ chain_name,
61
+ httpClient: { retries, get } = defaultHttpClient,
62
+ }: PremintSignatureGetPathParameters & {
63
+ httpClient?: Pick<IHttpClient, "retries" | "get">;
64
+ }): Promise<PremintSignatureGetResponse> =>
46
65
  retries(() =>
47
66
  get<PremintSignatureGetResponse>(
48
- `${ZORA_API_BASE}premint/signature/${path.chain_name}/${path.collection_address}/${path.uid}`,
67
+ `${ZORA_API_BASE}premint/signature/${chain_name}/${collection_address}/${uid}`,
49
68
  ),
50
69
  );
51
70
 
52
- export const PremintAPIClient = {
53
- postSignature,
54
- getSignature,
55
- getNextUID,
56
- };
57
- export { ZORA_API_BASE };
71
+ type OmitChainName<T> = Omit<T, "chain_name">;
72
+
73
+ class PremintAPIClient {
74
+ httpClient: IHttpClient;
75
+ networkConfig: NetworkConfig;
76
+
77
+ constructor(chainId: number, httpClient?: IHttpClient) {
78
+ this.httpClient = httpClient || defaultHttpClient;
79
+ this.networkConfig = getApiNetworkConfigForChain(chainId);
80
+ }
81
+ postSignature = async (
82
+ data: OmitChainName<PremintSignatureRequestBody>,
83
+ ): Promise<PremintSignatureResponse> =>
84
+ postSignature({
85
+ ...data,
86
+ chain_name: this.networkConfig.zoraBackendChainName,
87
+ httpClient: this.httpClient,
88
+ });
89
+
90
+ getNextUID = async (
91
+ path: OmitChainName<PremintNextUIDGetPathParameters>,
92
+ ): Promise<PremintNextUIDGetResponse> =>
93
+ getNextUID({
94
+ ...path,
95
+ chain_name: this.networkConfig.zoraBackendChainName,
96
+ httpClient: this.httpClient,
97
+ });
98
+
99
+ getSignature = async ({
100
+ collection_address,
101
+ uid,
102
+ }: OmitChainName<PremintSignatureGetPathParameters>): Promise<PremintSignatureGetResponse> =>
103
+ getSignature({
104
+ collection_address,
105
+ uid,
106
+ chain_name: this.networkConfig.zoraBackendChainName,
107
+ httpClient: this.httpClient,
108
+ });
109
+ }
110
+
111
+ export { ZORA_API_BASE, PremintAPIClient };