@zoralabs/protocol-sdk 0.9.0 → 0.9.2

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 (52) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/CHANGELOG.md +12 -0
  3. package/dist/anvil.d.ts.map +1 -1
  4. package/dist/apis/http-api-base.d.ts +1 -1
  5. package/dist/apis/http-api-base.d.ts.map +1 -1
  6. package/dist/apis/subgraph-querier.d.ts +6 -0
  7. package/dist/apis/subgraph-querier.d.ts.map +1 -1
  8. package/dist/create/1155-create-helper.d.ts +4 -1
  9. package/dist/create/1155-create-helper.d.ts.map +1 -1
  10. package/dist/create/contract-getter.d.ts +30 -0
  11. package/dist/create/contract-getter.d.ts.map +1 -0
  12. package/dist/create/contract-setup.d.ts +4 -8
  13. package/dist/create/contract-setup.d.ts.map +1 -1
  14. package/dist/create/mint-from-create.d.ts +12 -0
  15. package/dist/create/mint-from-create.d.ts.map +1 -0
  16. package/dist/create/subgraph-queries.d.ts +13 -0
  17. package/dist/create/subgraph-queries.d.ts.map +1 -0
  18. package/dist/create/types.d.ts +2 -0
  19. package/dist/create/types.d.ts.map +1 -1
  20. package/dist/index.cjs +267 -74
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.js +261 -68
  23. package/dist/index.js.map +1 -1
  24. package/dist/mint/mint-queries.d.ts +3 -1
  25. package/dist/mint/mint-queries.d.ts.map +1 -1
  26. package/dist/mint/subgraph-mint-getter.d.ts +2 -2
  27. package/dist/mint/subgraph-mint-getter.d.ts.map +1 -1
  28. package/dist/mint/subgraph-queries.d.ts +1 -5
  29. package/dist/mint/subgraph-queries.d.ts.map +1 -1
  30. package/dist/mint/types.d.ts +1 -0
  31. package/dist/mint/types.d.ts.map +1 -1
  32. package/dist/retries.d.ts +7 -0
  33. package/dist/retries.d.ts.map +1 -0
  34. package/dist/sdk.d.ts +2 -0
  35. package/dist/sdk.d.ts.map +1 -1
  36. package/package.json +1 -1
  37. package/src/apis/http-api-base.ts +12 -20
  38. package/src/apis/subgraph-querier.ts +7 -0
  39. package/src/create/1155-create-helper.test.ts +58 -59
  40. package/src/create/1155-create-helper.ts +37 -7
  41. package/src/create/contract-getter.ts +90 -0
  42. package/src/create/contract-setup.ts +17 -46
  43. package/src/create/mint-from-create.ts +111 -0
  44. package/src/create/subgraph-queries.ts +35 -0
  45. package/src/create/types.ts +2 -0
  46. package/src/mint/mint-queries.ts +8 -8
  47. package/src/mint/subgraph-mint-getter.ts +5 -2
  48. package/src/mint/subgraph-queries.ts +1 -7
  49. package/src/mint/types.ts +3 -0
  50. package/src/retries.ts +49 -0
  51. package/src/sdk.ts +8 -0
  52. package/test-integration/create-multiple-tokens-on-contract.ts +104 -0
@@ -18,52 +18,6 @@ export function new1155ContractVersion(chainId: number): string {
18
18
  return address.CONTRACT_1155_IMPL_VERSION;
19
19
  }
20
20
 
21
- export async function getContractInfoExistingContract({
22
- publicClient,
23
- contractAddress,
24
- }: {
25
- publicClient: Pick<PublicClient, "readContract">;
26
- contractAddress: Address;
27
- // Account that is the creator of the contract
28
- }): Promise<{
29
- contractVersion: string;
30
- contractName: string;
31
- nextTokenId: bigint;
32
- }> {
33
- // Check if contract exists either from metadata or the static address passed in.
34
- // If a static address is passed in, this fails if that contract does not exist.
35
- let contractVersion: string;
36
- try {
37
- contractVersion = await publicClient.readContract({
38
- abi: zoraCreator1155ImplABI,
39
- address: contractAddress,
40
- functionName: "contractVersion",
41
- });
42
- } catch (e: any) {
43
- // This logic branch is hit if the contract doesn't exist
44
- // falling back to contractExists to false.
45
- throw new Error(`Contract does not exist at ${contractAddress}`);
46
- }
47
-
48
- const nextTokenId = await publicClient.readContract({
49
- address: contractAddress,
50
- abi: zoraCreator1155ImplABI,
51
- functionName: "nextTokenId",
52
- });
53
-
54
- const contractName = await publicClient.readContract({
55
- address: contractAddress,
56
- abi: zoraCreator1155ImplABI,
57
- functionName: "name",
58
- });
59
-
60
- return {
61
- contractVersion,
62
- contractName,
63
- nextTokenId,
64
- };
65
- }
66
-
67
21
  export async function getDeterministicContractAddress({
68
22
  publicClient,
69
23
  account,
@@ -96,3 +50,20 @@ export async function getDeterministicContractAddress({
96
50
 
97
51
  return contractAddress;
98
52
  }
53
+
54
+ export async function getNewContractMintFee({
55
+ publicClient,
56
+ chainId,
57
+ }: {
58
+ publicClient: Pick<PublicClient, "readContract">;
59
+ chainId: number;
60
+ }) {
61
+ const implAddress = contracts1155.addresses[chainId as contracts1155Address]
62
+ .CONTRACT_1155_IMPL as Address;
63
+
64
+ return await publicClient.readContract({
65
+ abi: zoraCreator1155ImplABI,
66
+ address: implAddress,
67
+ functionName: "mintFee",
68
+ });
69
+ }
@@ -0,0 +1,111 @@
1
+ import { Address, parseEther, zeroAddress } from "viem";
2
+ import { ConcreteSalesConfig } from "./types";
3
+ import {
4
+ AsyncPrepareMint,
5
+ MintParametersBase,
6
+ OnchainSalesStrategies,
7
+ PrepareMintReturn,
8
+ } from "src/mint/types";
9
+ import {
10
+ makePrepareMint1155TokenParams,
11
+ parseMintCosts,
12
+ } from "src/mint/mint-transactions";
13
+ import { getRequiredErc20Approvals } from "src/mint/mint-queries";
14
+
15
+ async function toSalesStrategyFromSubgraph({
16
+ minter,
17
+ salesConfig,
18
+ getContractMintFee,
19
+ }: {
20
+ minter: Address;
21
+ salesConfig: ConcreteSalesConfig;
22
+ getContractMintFee: () => Promise<bigint>;
23
+ }): Promise<OnchainSalesStrategies> {
24
+ if (salesConfig.type === "timed") {
25
+ return {
26
+ saleType: "timed",
27
+ address: minter,
28
+ // for now we hardcode this
29
+ mintFeePerQuantity: parseEther("0.000111"),
30
+ saleStart: salesConfig.saleStart.toString(),
31
+ saleEnd: salesConfig.saleEnd.toString(),
32
+ // the following are not needed for now but we wanna satisfy concrete
33
+ erc20Z: zeroAddress,
34
+ mintFee: 0n,
35
+ pool: zeroAddress,
36
+ secondaryActivated: false,
37
+ };
38
+ }
39
+ if (salesConfig.type === "erc20Mint") {
40
+ return {
41
+ saleType: "erc20",
42
+ address: minter,
43
+ mintFeePerQuantity: 0n,
44
+ saleStart: salesConfig.saleStart.toString(),
45
+ saleEnd: salesConfig.saleEnd.toString(),
46
+ currency: salesConfig.currency,
47
+ pricePerToken: salesConfig.pricePerToken,
48
+ maxTokensPerAddress: salesConfig.maxTokensPerAddress,
49
+ };
50
+ }
51
+ const contractMintFee = await getContractMintFee();
52
+ if (salesConfig.type === "fixedPrice") {
53
+ return {
54
+ saleType: "fixedPrice",
55
+ address: minter,
56
+ maxTokensPerAddress: salesConfig.maxTokensPerAddress,
57
+ mintFeePerQuantity: contractMintFee,
58
+ pricePerToken: salesConfig.pricePerToken,
59
+ saleStart: salesConfig.saleStart.toString(),
60
+ saleEnd: salesConfig.saleEnd.toString(),
61
+ };
62
+ }
63
+ return {
64
+ saleType: "allowlist",
65
+ address: minter,
66
+ saleStart: salesConfig.saleStart.toString(),
67
+ saleEnd: salesConfig.saleEnd.toString(),
68
+ merkleRoot: salesConfig.presaleMerkleRoot,
69
+ mintFeePerQuantity: contractMintFee,
70
+ };
71
+ }
72
+ export function makeOnchainPrepareMintFromCreate({
73
+ contractAddress,
74
+ tokenId,
75
+ result,
76
+ minter,
77
+ getContractMintFee,
78
+ contractVersion,
79
+ }: {
80
+ contractAddress: Address;
81
+ tokenId: bigint;
82
+ result: ConcreteSalesConfig;
83
+ minter: Address;
84
+ getContractMintFee: () => Promise<bigint>;
85
+ contractVersion: string;
86
+ }): AsyncPrepareMint {
87
+ return async (params: MintParametersBase): Promise<PrepareMintReturn> => {
88
+ const subgraphSalesConfig = await toSalesStrategyFromSubgraph({
89
+ minter,
90
+ getContractMintFee,
91
+ salesConfig: result,
92
+ });
93
+ return {
94
+ parameters: makePrepareMint1155TokenParams({
95
+ salesConfigAndTokenInfo: {
96
+ salesConfig: subgraphSalesConfig,
97
+ contractVersion,
98
+ },
99
+ ...params,
100
+ tokenContract: contractAddress,
101
+ tokenId,
102
+ }),
103
+ costs: parseMintCosts({
104
+ allowListEntry: params.allowListEntry,
105
+ quantityToMint: BigInt(params.quantityToMint),
106
+ salesConfig: subgraphSalesConfig,
107
+ }),
108
+ erc20Approval: getRequiredErc20Approvals(params, subgraphSalesConfig),
109
+ };
110
+ };
111
+ }
@@ -0,0 +1,35 @@
1
+ import { ISubgraphQuery } from "src/apis/subgraph-querier";
2
+ import { Address } from "viem";
3
+
4
+ export function buildContractInfoQuery({
5
+ contractAddress,
6
+ }: {
7
+ contractAddress: Address;
8
+ }): ISubgraphQuery<{
9
+ name: string;
10
+ contractVersion: string;
11
+ mintFeePerQuantity: string;
12
+ tokens: {
13
+ tokenId: Address;
14
+ }[];
15
+ }> {
16
+ return {
17
+ query: `
18
+ query ($contractAddress: Bytes!) {
19
+ zoraCreateContract(id: $contractAddress) {
20
+ contractVersion
21
+ name
22
+ mintFeePerQuantity
23
+ tokens(first: 1, orderBy: tokenId, orderDirection: desc) {
24
+ tokenId
25
+ }
26
+ }
27
+ }
28
+ `,
29
+ variables: {
30
+ contractAddress: contractAddress.toLowerCase(),
31
+ },
32
+ parseResponseData: (responseData: any | undefined) =>
33
+ responseData.zoraCreateContract,
34
+ };
35
+ }
@@ -1,3 +1,4 @@
1
+ import { AsyncPrepareMint } from "src/mint/types";
1
2
  import { Concrete } from "src/utils";
2
3
  import { Account, Address, Hex, SimulateContractParameters } from "viem";
3
4
 
@@ -119,6 +120,7 @@ export type CreateNew1155TokenReturn = {
119
120
  newToken: New1155Token;
120
121
  minter: Address;
121
122
  contractVersion: string;
123
+ prepareMint: AsyncPrepareMint;
122
124
  };
123
125
 
124
126
  export type CreateNew1155ContractAndTokenReturn = {
@@ -261,7 +261,7 @@ function parsePremint({
261
261
  throw new Error("Invalid premint config version");
262
262
  }
263
263
 
264
- const makeOnchainPrepareMint =
264
+ export const makeOnchainPrepareMint =
265
265
  (result: OnchainSalesConfigAndTokenInfo): PrepareMint =>
266
266
  (params: MintParametersBase) => {
267
267
  if (!result.salesConfig) {
@@ -273,7 +273,7 @@ const makeOnchainPrepareMint =
273
273
  token: result as Concrete<OnchainSalesConfigAndTokenInfo>,
274
274
  mintParams: params,
275
275
  }),
276
- erc20Approval: getRequiredErc20Approvals(params, result),
276
+ erc20Approval: getRequiredErc20Approvals(params, result.salesConfig),
277
277
  costs: parseMintCosts({
278
278
  salesConfig: result.salesConfig,
279
279
  quantityToMint: BigInt(params.quantityToMint),
@@ -327,15 +327,15 @@ function toPremintMintReturn({
327
327
  prepareMint: makePremintPrepareMint(mintable, mintFee, premint),
328
328
  };
329
329
  }
330
- function getRequiredErc20Approvals(
330
+ export function getRequiredErc20Approvals(
331
331
  params: MintParametersBase,
332
- result: OnchainSalesConfigAndTokenInfo,
332
+ salesConfig: OnchainSalesConfigAndTokenInfo["salesConfig"],
333
333
  ): Erc20Approval | undefined {
334
- if (result.salesConfig?.saleType !== "erc20") return undefined;
334
+ if (salesConfig?.saleType !== "erc20") return undefined;
335
335
 
336
336
  return {
337
- quantity: result.salesConfig.pricePerToken * BigInt(params.quantityToMint),
338
- approveTo: result.salesConfig.address,
339
- erc20: result.salesConfig.currency,
337
+ quantity: salesConfig.pricePerToken * BigInt(params.quantityToMint),
338
+ approveTo: salesConfig.address,
339
+ erc20: salesConfig.currency,
340
340
  };
341
341
  }
@@ -1,6 +1,10 @@
1
1
  import { Address } from "viem";
2
2
  import { httpClient as defaultHttpClient } from "../apis/http-api-base";
3
- import { ISubgraphQuerier, SubgraphQuerier } from "../apis/subgraph-querier";
3
+ import {
4
+ ISubgraphQuerier,
5
+ ISubgraphQuery,
6
+ SubgraphQuerier,
7
+ } from "../apis/subgraph-querier";
4
8
  import { NetworkConfig, networkConfigByChain } from "src/apis/chain-constants";
5
9
  import { GenericTokenIdTypes } from "src/types";
6
10
  import {
@@ -14,7 +18,6 @@ import {
14
18
  buildContractTokensQuery,
15
19
  buildNftTokenSalesQuery,
16
20
  buildPremintsOfContractQuery,
17
- ISubgraphQuery,
18
21
  SalesStrategyResult,
19
22
  TokenQueryResult,
20
23
  } from "./subgraph-queries";
@@ -1,3 +1,4 @@
1
+ import { ISubgraphQuery } from "src/apis/subgraph-querier";
1
2
  import { GenericTokenIdTypes } from "src/types";
2
3
  import { Address } from "viem";
3
4
 
@@ -189,13 +190,6 @@ query ($contract: Bytes!) {
189
190
  responseData?.zoraCreateTokens,
190
191
  };
191
192
  }
192
-
193
- export type ISubgraphQuery<T> = {
194
- query: string;
195
- variables: Record<string, any>;
196
- parseResponseData: (data: any | undefined) => T | undefined;
197
- };
198
-
199
193
  export function buildPremintsOfContractQuery({
200
194
  tokenAddress,
201
195
  }: {
package/src/mint/types.ts CHANGED
@@ -269,6 +269,9 @@ export type PrepareMintReturn = {
269
269
  };
270
270
 
271
271
  export type PrepareMint = (params: MintParametersBase) => PrepareMintReturn;
272
+ export type AsyncPrepareMint = (
273
+ params: MintParametersBase,
274
+ ) => Promise<PrepareMintReturn>;
272
275
 
273
276
  export type MintableReturn = {
274
277
  /** Token information */
package/src/retries.ts ADDED
@@ -0,0 +1,49 @@
1
+ async function wait(delayMs: number) {
2
+ return new Promise((resolve) => {
3
+ setTimeout(resolve, delayMs);
4
+ });
5
+ }
6
+
7
+ const retryInternal = async <T>({
8
+ tryFn,
9
+ maxTries = 3,
10
+ atTry,
11
+ linearBackoffMS = 200,
12
+ shouldRetryOnError = () => true,
13
+ }: {
14
+ tryFn: () => T;
15
+ maxTries?: number;
16
+ atTry: number;
17
+ linearBackoffMS?: number;
18
+ shouldRetryOnError?: (err: any) => boolean;
19
+ }): Promise<T> => {
20
+ try {
21
+ return await tryFn();
22
+ } catch (err: any) {
23
+ if (shouldRetryOnError(err)) {
24
+ if (atTry <= maxTries) {
25
+ await wait(atTry * linearBackoffMS);
26
+ return await retryInternal({
27
+ tryFn,
28
+ maxTries,
29
+ atTry: atTry + 1,
30
+ linearBackoffMS,
31
+ shouldRetryOnError,
32
+ });
33
+ }
34
+ }
35
+ throw err;
36
+ }
37
+ };
38
+
39
+ export const retriesGeneric = async <T>(params: {
40
+ tryFn: () => T;
41
+ maxTries?: number;
42
+ linearBackoffMS?: number;
43
+ shouldRetryOnError?: (err: any) => boolean;
44
+ }) => {
45
+ return retryInternal({
46
+ ...params,
47
+ atTry: 1,
48
+ });
49
+ };
package/src/sdk.ts CHANGED
@@ -8,6 +8,10 @@ import { ClientConfig } from "./utils";
8
8
  import { IPremintAPI, PremintAPIClient } from "./premint/premint-api-client";
9
9
  import { SubgraphMintGetter } from "./mint/subgraph-mint-getter";
10
10
  import { IOnchainMintGetter } from "./mint/types";
11
+ import {
12
+ IContractGetter,
13
+ SubgraphContractGetter,
14
+ } from "./create/contract-getter";
11
15
 
12
16
  export type CreatorClient = {
13
17
  createPremint: PremintClient["createPremint"];
@@ -29,6 +33,7 @@ export type CollectorClient = {
29
33
  export type CreatorClientConfig = ClientConfig & {
30
34
  /** API for submitting and getting premints. Defaults to the Zora Premint API */
31
35
  premintApi?: IPremintAPI;
36
+ contractGetter?: IContractGetter;
32
37
  };
33
38
 
34
39
  /**
@@ -50,6 +55,9 @@ export function createCreatorClient(
50
55
  const create1155CreatorClient = new Create1155Client({
51
56
  chainId: clientConfig.chainId,
52
57
  publicClient: clientConfig.publicClient,
58
+ contractGetter:
59
+ clientConfig.contractGetter ||
60
+ new SubgraphContractGetter(clientConfig.chainId),
53
61
  });
54
62
 
55
63
  return {
@@ -0,0 +1,104 @@
1
+ import { createCreatorClient } from "src";
2
+ import {
3
+ Address,
4
+ Chain,
5
+ LocalAccount,
6
+ createPublicClient,
7
+ createWalletClient,
8
+ http,
9
+ } from "viem";
10
+ import { privateKeyToAccount } from "viem/accounts";
11
+ import { zoraSepolia } from "viem/chains";
12
+
13
+ const publicClient = createPublicClient({
14
+ chain: zoraSepolia as Chain,
15
+ transport: http(),
16
+ });
17
+
18
+ const walletClient = createWalletClient({
19
+ chain: zoraSepolia,
20
+ transport: http(),
21
+ });
22
+
23
+ const creatorClient = createCreatorClient({
24
+ chainId: zoraSepolia.id,
25
+ publicClient,
26
+ });
27
+
28
+ export const createMultipleTokensOnContract = async ({
29
+ creatorAccount,
30
+ }: {
31
+ creatorAccount: LocalAccount;
32
+ }) => {
33
+ console.log({ address: creatorAccount.address });
34
+ const { contractAddress, parameters } = await creatorClient.create1155({
35
+ account: creatorAccount.address,
36
+ contract: {
37
+ name: "testContractD",
38
+ uri: "ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
39
+ },
40
+ token: {
41
+ tokenMetadataURI:
42
+ "ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
43
+ },
44
+ });
45
+ console.log("creating contract and token");
46
+
47
+ const { request: requestA } = await publicClient.simulateContract(parameters);
48
+
49
+ const hashA = await walletClient.writeContract({
50
+ ...requestA,
51
+ account: creatorAccount,
52
+ });
53
+
54
+ const receiptA = await publicClient.waitForTransactionReceipt({
55
+ hash: hashA,
56
+ });
57
+
58
+ if (receiptA.status !== "success") {
59
+ throw new Error("create new contract failed");
60
+ }
61
+
62
+ console.log("creating new token on contract");
63
+
64
+ const { parameters: parametersB } =
65
+ await creatorClient.create1155OnExistingContract({
66
+ account: creatorAccount.address,
67
+ contractAddress,
68
+ token: {
69
+ tokenMetadataURI:
70
+ "ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
71
+ },
72
+ });
73
+
74
+ const { request: requestB } =
75
+ await publicClient.simulateContract(parametersB);
76
+
77
+ const hashB = await walletClient.writeContract({
78
+ ...requestB,
79
+ account: creatorAccount,
80
+ });
81
+
82
+ const receiptB = await publicClient.waitForTransactionReceipt({
83
+ hash: hashB,
84
+ });
85
+
86
+ if (receiptB.status !== "success") {
87
+ throw new Error("create token on contract failed");
88
+ }
89
+
90
+ console.log("created multiple tokens on contract");
91
+ };
92
+
93
+ const setupTestContracts = async () => {
94
+ const creatorAccount = privateKeyToAccount(
95
+ process.env.VITE_PRIVATE_KEY! as Address,
96
+ );
97
+
98
+ // create 2 premints on a contract
99
+ await createMultipleTokensOnContract({
100
+ creatorAccount,
101
+ });
102
+ };
103
+
104
+ setupTestContracts();