@zoralabs/protocol-sdk 0.9.1 → 0.9.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.
Files changed (50) 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 +3 -3
  15. package/dist/create/mint-from-create.d.ts.map +1 -1
  16. package/dist/create/minter-defaults.d.ts +1 -1
  17. package/dist/create/minter-defaults.d.ts.map +1 -1
  18. package/dist/create/subgraph-queries.d.ts +13 -0
  19. package/dist/create/subgraph-queries.d.ts.map +1 -0
  20. package/dist/create/token-setup.d.ts +2 -0
  21. package/dist/create/token-setup.d.ts.map +1 -1
  22. package/dist/index.cjs +2166 -2099
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.js +2188 -2121
  25. package/dist/index.js.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/retries.d.ts +7 -0
  31. package/dist/retries.d.ts.map +1 -0
  32. package/dist/sdk.d.ts +2 -0
  33. package/dist/sdk.d.ts.map +1 -1
  34. package/package.json +1 -1
  35. package/src/apis/http-api-base.ts +12 -20
  36. package/src/apis/subgraph-querier.ts +7 -0
  37. package/src/create/1155-create-helper.test.ts +68 -3
  38. package/src/create/1155-create-helper.ts +23 -9
  39. package/src/create/contract-getter.ts +90 -0
  40. package/src/create/contract-setup.ts +17 -46
  41. package/src/create/mint-from-create.ts +7 -15
  42. package/src/create/minter-defaults.ts +11 -20
  43. package/src/create/subgraph-queries.ts +35 -0
  44. package/src/create/token-setup.ts +5 -1
  45. package/src/create/types.ts +1 -1
  46. package/src/mint/subgraph-mint-getter.ts +5 -2
  47. package/src/mint/subgraph-queries.ts +1 -7
  48. package/src/retries.ts +49 -0
  49. package/src/sdk.ts +8 -0
  50. package/test-integration/create-multiple-tokens-on-contract.ts +104 -0
@@ -9,7 +9,6 @@ import {
9
9
  ConcreteSalesConfig,
10
10
  TimedSaleParamsType,
11
11
  } from "./types";
12
- import { fetchTokenMetadata } from "src/ipfs/token-metadata";
13
12
 
14
13
  // Sales end forever amount (uint64 max)
15
14
  export const SALE_END_FOREVER = 18446744073709551615n;
@@ -75,30 +74,19 @@ export const parseNameIntoSymbol = (name: string) => {
75
74
  return result;
76
75
  };
77
76
 
78
- async function fetchTokenNameFromMetadata(
79
- tokenMetadataURI: string,
80
- ): Promise<string> {
81
- const tokenMetadata = await fetchTokenMetadata(tokenMetadataURI);
82
-
83
- if (!tokenMetadata.name) {
84
- throw new Error("No name found in token metadata");
85
- }
86
-
87
- return tokenMetadata.name;
88
- }
89
77
  const timedSaleSettingsWithDefaults = async (
90
78
  params: TimedSaleParamsType,
91
- tokenMetadataURI: string,
79
+ contractName: string,
92
80
  ): Promise<Concrete<TimedSaleParamsType>> => {
93
81
  // If the name is not provided, try to fetch it from the metadata
94
- const erc20Name =
95
- params.erc20Name || (await fetchTokenNameFromMetadata(tokenMetadataURI));
82
+ const erc20Name = params.erc20Name || contractName;
96
83
  const symbol = params.erc20Symbol || parseNameIntoSymbol(erc20Name);
97
84
 
98
85
  return {
99
86
  type: "timed",
100
87
  ...DEFAULT_SALE_START_AND_END,
101
- erc20Name,
88
+ ...params,
89
+ erc20Name: erc20Name,
102
90
  erc20Symbol: symbol,
103
91
  };
104
92
  };
@@ -112,14 +100,17 @@ const isErc20 = (
112
100
  const isFixedPrice = (
113
101
  salesConfig: SalesConfigParamsType,
114
102
  ): salesConfig is FixedPriceParamsType => {
115
- return (salesConfig as FixedPriceParamsType).pricePerToken > 0n;
103
+ return (
104
+ salesConfig.type === "fixedPrice" ||
105
+ (salesConfig as FixedPriceParamsType).pricePerToken > 0n
106
+ );
116
107
  };
117
108
 
118
109
  export const getSalesConfigWithDefaults = async (
119
110
  salesConfig: SalesConfigParamsType | undefined,
120
- tokenMetadataURI: string,
111
+ contractName: string,
121
112
  ): Promise<ConcreteSalesConfig> => {
122
- if (!salesConfig) return timedSaleSettingsWithDefaults({}, tokenMetadataURI);
113
+ if (!salesConfig) return timedSaleSettingsWithDefaults({}, contractName);
123
114
  if (isAllowList(salesConfig)) {
124
115
  return allowListWithDefaults(salesConfig);
125
116
  }
@@ -130,5 +121,5 @@ export const getSalesConfigWithDefaults = async (
130
121
  return fixedPriceSettingsWithDefaults(salesConfig);
131
122
  }
132
123
 
133
- return timedSaleSettingsWithDefaults(salesConfig, tokenMetadataURI);
124
+ return timedSaleSettingsWithDefaults(salesConfig, contractName);
134
125
  };
@@ -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
+ }
@@ -9,6 +9,7 @@ import { setupMinters } from "./minter-setup";
9
9
  async function applyNew1155Defaults(
10
10
  props: CreateNew1155TokenProps,
11
11
  ownerAddress: Address,
12
+ contractName: string,
12
13
  ): Promise<New1155Token> {
13
14
  const { payoutRecipient: fundsRecipient } = props;
14
15
  const fundsRecipientOrOwner =
@@ -26,7 +27,7 @@ async function applyNew1155Defaults(
26
27
  tokenMetadataURI: props.tokenMetadataURI,
27
28
  salesConfig: await getSalesConfigWithDefaults(
28
29
  props.salesConfig,
29
- props.tokenMetadataURI,
30
+ contractName,
30
31
  ),
31
32
  };
32
33
  }
@@ -117,6 +118,8 @@ export async function constructCreate1155TokenCalls(
117
118
  ContractProps & {
118
119
  ownerAddress: Address;
119
120
  chainId: number;
121
+ } & {
122
+ contractName: string;
120
123
  },
121
124
  ): Promise<{
122
125
  setupActions: `0x${string}`[];
@@ -134,6 +137,7 @@ export async function constructCreate1155TokenCalls(
134
137
  const new1155TokenPropsWithDefaults = await applyNew1155Defaults(
135
138
  props,
136
139
  ownerAddress,
140
+ props.contractName,
137
141
  );
138
142
 
139
143
  const verifyTokenIdExpected = encodeFunctionData({
@@ -29,7 +29,7 @@ export type FixedPriceParamsType = SaleStartAndEnd &
29
29
 
30
30
  export type TimedSaleParamsType = SaleStartAndEnd & {
31
31
  type?: "timed";
32
- // Name of the erc20z token to create for the secondary sale. If not provided, fetches the metadata from the tokenMetadataURI and uses the name from it.
32
+ // Name of the erc20z token to create for the secondary sale. If not provided, uses the contract name
33
33
  erc20Name?: string;
34
34
  // Symbol of the erc20z token to create for the secondary sale. If not provided, extracts it from the name.
35
35
  erc20Symbol?: string;
@@ -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/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();