@zoralabs/protocol-sdk 0.7.6 → 0.9.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.
Files changed (80) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/CHANGELOG.md +17 -0
  3. package/dist/allow-list/allow-list-client.d.ts +26 -0
  4. package/dist/allow-list/allow-list-client.d.ts.map +1 -0
  5. package/dist/allow-list/types.d.ts +14 -0
  6. package/dist/allow-list/types.d.ts.map +1 -0
  7. package/dist/apis/generated/allow-list-api-types.d.ts +288 -0
  8. package/dist/apis/generated/allow-list-api-types.d.ts.map +1 -0
  9. package/dist/apis/http-api-base.d.ts.map +1 -1
  10. package/dist/apis/subgraph-querier.d.ts +18 -0
  11. package/dist/apis/subgraph-querier.d.ts.map +1 -0
  12. package/dist/create/1155-create-helper.d.ts +14 -11
  13. package/dist/create/1155-create-helper.d.ts.map +1 -1
  14. package/dist/create/contract-setup.d.ts +13 -8
  15. package/dist/create/contract-setup.d.ts.map +1 -1
  16. package/dist/create/minter-defaults.d.ts +5 -0
  17. package/dist/create/minter-defaults.d.ts.map +1 -0
  18. package/dist/create/minter-setup.d.ts +14 -0
  19. package/dist/create/minter-setup.d.ts.map +1 -0
  20. package/dist/create/token-setup.d.ts +4 -19
  21. package/dist/create/token-setup.d.ts.map +1 -1
  22. package/dist/create/types.d.ts +53 -13
  23. package/dist/create/types.d.ts.map +1 -1
  24. package/dist/create/update.d.ts +15 -0
  25. package/dist/create/update.d.ts.map +1 -0
  26. package/dist/index.cjs +1660 -1246
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +1681 -1264
  31. package/dist/index.js.map +1 -1
  32. package/dist/ipfs/token-metadata.d.ts +1 -0
  33. package/dist/ipfs/token-metadata.d.ts.map +1 -1
  34. package/dist/mint/mint-client.d.ts +2 -6
  35. package/dist/mint/mint-client.d.ts.map +1 -1
  36. package/dist/mint/mint-queries.d.ts +3 -1
  37. package/dist/mint/mint-queries.d.ts.map +1 -1
  38. package/dist/mint/mint-transactions.d.ts +9 -7
  39. package/dist/mint/mint-transactions.d.ts.map +1 -1
  40. package/dist/mint/subgraph-mint-getter.d.ts +5 -4
  41. package/dist/mint/subgraph-mint-getter.d.ts.map +1 -1
  42. package/dist/mint/subgraph-queries.d.ts +42 -15
  43. package/dist/mint/subgraph-queries.d.ts.map +1 -1
  44. package/dist/mint/types.d.ts +32 -13
  45. package/dist/mint/types.d.ts.map +1 -1
  46. package/dist/sdk.d.ts +2 -1
  47. package/dist/sdk.d.ts.map +1 -1
  48. package/dist/sparks/sparks-contracts.d.ts +96 -96
  49. package/dist/types.d.ts +1 -1
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/utils.d.ts +1 -8
  52. package/dist/utils.d.ts.map +1 -1
  53. package/package.json +2 -3
  54. package/src/allow-list/allow-list-client.ts +105 -0
  55. package/src/allow-list/types.ts +15 -0
  56. package/src/apis/generated/allow-list-api-types.ts +288 -0
  57. package/src/apis/http-api-base.ts +12 -0
  58. package/src/apis/subgraph-querier.ts +38 -0
  59. package/src/create/1155-create-helper.test.ts +269 -113
  60. package/src/create/1155-create-helper.ts +204 -90
  61. package/src/create/contract-setup.ts +54 -44
  62. package/src/create/minter-defaults.test.ts +21 -0
  63. package/src/create/minter-defaults.ts +134 -0
  64. package/src/create/minter-setup.ts +293 -0
  65. package/src/create/token-setup.ts +14 -190
  66. package/src/create/types.ts +94 -25
  67. package/src/create/update.ts +93 -0
  68. package/src/index.ts +4 -0
  69. package/src/ipfs/token-metadata.ts +18 -0
  70. package/src/mint/mint-client.test.ts +219 -15
  71. package/src/mint/mint-client.ts +2 -34
  72. package/src/mint/mint-queries.ts +34 -13
  73. package/src/mint/mint-transactions.ts +104 -17
  74. package/src/mint/subgraph-mint-getter.ts +107 -50
  75. package/src/mint/subgraph-queries.ts +67 -37
  76. package/src/mint/types.ts +55 -16
  77. package/src/premint/premint-client.test.ts +6 -5
  78. package/src/sdk.ts +5 -2
  79. package/src/types.ts +1 -1
  80. package/src/utils.ts +1 -25
@@ -8,13 +8,23 @@ import type {
8
8
  Address,
9
9
  Hex,
10
10
  PublicClient,
11
- SimulateContractParameters,
12
11
  TransactionReceipt,
13
12
  } from "viem";
14
13
  import { decodeEventLog } from "viem";
15
14
  import { makeContractParameters } from "src/utils";
16
- import { getContractInfo } from "./contract-setup";
17
- import { ContractType, CreateNew1155Params, New1155Token } from "./types";
15
+ import {
16
+ getContractInfoExistingContract,
17
+ getDeterministicContractAddress,
18
+ new1155ContractVersion,
19
+ } from "./contract-setup";
20
+ import {
21
+ CreateNew1155ContractAndTokenReturn,
22
+ CreateNew1155ContractParams,
23
+ CreateNew1155ParamsBase,
24
+ CreateNew1155TokenParams,
25
+ CreateNew1155TokenReturn,
26
+ NewContractParams,
27
+ } from "./types";
18
28
  import { constructCreate1155TokenCalls } from "./token-setup";
19
29
 
20
30
  // Default royalty bps
@@ -22,7 +32,7 @@ const ROYALTY_BPS_DEFAULT = 1000;
22
32
 
23
33
  export const getTokenIdFromCreateReceipt = (
24
34
  receipt: TransactionReceipt,
25
- ): bigint | undefined => {
35
+ ): bigint => {
26
36
  for (const data of receipt.logs) {
27
37
  try {
28
38
  const decodedLog = decodeEventLog({
@@ -35,73 +45,84 @@ export const getTokenIdFromCreateReceipt = (
35
45
  }
36
46
  } catch (err: any) {}
37
47
  }
48
+
49
+ throw new Error(
50
+ "No event found in receipt that could be used to get tokenId",
51
+ );
52
+ };
53
+
54
+ export const getContractAddressFromReceipt = (
55
+ receipt: TransactionReceipt,
56
+ ): Address => {
57
+ for (const data of receipt.logs) {
58
+ try {
59
+ const decodedLog = decodeEventLog({
60
+ abi: zoraCreator1155FactoryImplABI,
61
+ eventName: "SetupNewContract",
62
+ ...data,
63
+ });
64
+ if (decodedLog && decodedLog.eventName === "SetupNewContract") {
65
+ return decodedLog.args.newContract;
66
+ }
67
+ } catch (err: any) {}
68
+ }
69
+
70
+ throw new Error(
71
+ "No event found in receipt that could be used to get contract address",
72
+ );
38
73
  };
39
74
 
40
- type CreateNew1155TokenReturn = {
41
- parameters: SimulateContractParameters<
42
- any,
43
- any,
44
- any,
45
- any,
46
- any,
47
- Account | Address
48
- >;
75
+ type MakeContractParametersBase = {
76
+ account: Address | Account;
77
+
49
78
  tokenSetupActions: Hex[];
50
- collectionAddress: Address;
51
- newTokenId: bigint;
52
- newToken: New1155Token;
53
- minter: Address;
54
- contractExists: boolean;
55
79
  };
56
80
 
57
- function makeCreateContractAndTokenCall({
58
- contractExists,
59
- contractAddress,
60
- contract,
81
+ export function makeCreateContractAndTokenCall({
61
82
  account,
83
+ contract,
62
84
  royaltyBPS,
63
- tokenSetupActions,
64
85
  fundsRecipient,
86
+ tokenSetupActions,
87
+ chainId,
65
88
  }: {
66
- contractExists: boolean;
67
- contractAddress: Address;
68
- contract: ContractType;
69
- account: Address | Account;
89
+ chainId: number;
90
+ contract: NewContractParams;
70
91
  royaltyBPS?: number;
71
92
  fundsRecipient?: Address;
72
- tokenSetupActions: Hex[];
73
- }) {
74
- if (!contractAddress && typeof contract === "string") {
75
- throw new Error("Invariant: contract cannot be missing and an address");
76
- }
77
-
78
- if (!contractExists) {
79
- if (typeof contract === "string") {
80
- throw new Error("Invariant: expected contract object");
81
- }
82
-
83
- const accountAddress =
84
- typeof account === "string" ? account : account.address;
85
- return makeContractParameters({
86
- abi: zoraCreator1155FactoryImplABI,
87
- functionName: "createContractDeterministic",
88
- account,
89
- address: zoraCreator1155FactoryImplAddress[999],
90
- args: [
91
- contract.uri,
92
- contract.name,
93
- {
94
- // deprecated
95
- royaltyMintSchedule: 0,
96
- royaltyBPS: royaltyBPS || ROYALTY_BPS_DEFAULT,
97
- royaltyRecipient: fundsRecipient || accountAddress,
98
- },
99
- contract.defaultAdmin || accountAddress,
100
- tokenSetupActions,
93
+ } & MakeContractParametersBase) {
94
+ const accountAddress =
95
+ typeof account === "string" ? account : account.address;
96
+ return makeContractParameters({
97
+ abi: zoraCreator1155FactoryImplABI,
98
+ functionName: "createContractDeterministic",
99
+ account,
100
+ address:
101
+ zoraCreator1155FactoryImplAddress[
102
+ chainId as keyof typeof zoraCreator1155FactoryImplAddress
101
103
  ],
102
- });
103
- }
104
+ args: [
105
+ contract.uri,
106
+ contract.name,
107
+ {
108
+ // deprecated
109
+ royaltyMintSchedule: 0,
110
+ royaltyBPS: royaltyBPS || ROYALTY_BPS_DEFAULT,
111
+ royaltyRecipient: fundsRecipient || accountAddress,
112
+ },
113
+ contract.defaultAdmin || accountAddress,
114
+ tokenSetupActions,
115
+ ],
116
+ });
117
+ }
104
118
 
119
+ function makeCreateTokenCall({
120
+ contractAddress,
121
+ account,
122
+ tokenSetupActions,
123
+ }: {
124
+ contractAddress: Address;
125
+ } & MakeContractParametersBase) {
105
126
  return makeContractParameters({
106
127
  abi: zoraCreator1155ImplABI,
107
128
  functionName: "multicall",
@@ -126,73 +147,166 @@ export class Create1155Client {
126
147
  this.publicClient = publicClient;
127
148
  }
128
149
 
129
- async createNew1155Token(props: CreateNew1155Params) {
130
- return createNew1155Token({
150
+ async createNew1155(
151
+ props: CreateNew1155ContractParams,
152
+ ): Promise<CreateNew1155ContractAndTokenReturn> {
153
+ return createNew1155ContractAndToken({
131
154
  ...props,
132
155
  publicClient: this.publicClient,
133
156
  chainId: this.chainId,
134
157
  });
135
158
  }
159
+
160
+ async createNew1155OnExistingContract({
161
+ contractAddress: contract,
162
+ account,
163
+ token,
164
+ getAdditionalSetupActions,
165
+ }: CreateNew1155TokenParams): Promise<CreateNew1155TokenReturn> {
166
+ return createNew1155Token({
167
+ contractAddress: contract,
168
+ account,
169
+ token,
170
+ getAdditionalSetupActions,
171
+ publicClient: this.publicClient,
172
+ chainId: this.chainId,
173
+ });
174
+ }
136
175
  }
137
176
 
138
- async function createNew1155Token({
177
+ async function createNew1155ContractAndToken({
139
178
  contract,
140
179
  account,
180
+ chainId,
181
+ token,
182
+ publicClient,
183
+ getAdditionalSetupActions,
184
+ }: CreateNew1155ContractParams & {
185
+ publicClient: Pick<PublicClient, "readContract">;
186
+ chainId: number;
187
+ }): Promise<CreateNew1155ContractAndTokenReturn> {
188
+ const nextTokenId = 1n;
189
+ const contractVersion = new1155ContractVersion(chainId);
190
+
191
+ const {
192
+ minter,
193
+ newToken,
194
+ setupActions: tokenSetupActions,
195
+ } = await prepareSetupActions({
196
+ chainId,
197
+ account,
198
+ contractVersion,
199
+ nextTokenId,
200
+ token,
201
+ getAdditionalSetupActions,
202
+ });
203
+
204
+ const request = makeCreateContractAndTokenCall({
205
+ contract,
206
+ account,
207
+ chainId,
208
+ tokenSetupActions,
209
+ fundsRecipient: token.payoutRecipient,
210
+ royaltyBPS: token.royaltyBPS,
211
+ });
212
+
213
+ const contractAddress = await getDeterministicContractAddress({
214
+ account,
215
+ publicClient,
216
+ setupActions: tokenSetupActions,
217
+ chainId,
218
+ contract,
219
+ });
220
+
221
+ return {
222
+ parameters: request,
223
+ tokenSetupActions,
224
+ newTokenId: nextTokenId,
225
+ newToken,
226
+ contractAddress: contractAddress,
227
+ contractVersion,
228
+ minter,
229
+ };
230
+ }
231
+
232
+ async function createNew1155Token({
233
+ contractAddress: contractAddress,
234
+ account,
141
235
  getAdditionalSetupActions,
142
- token: tokenConfig,
236
+ token,
143
237
  publicClient,
144
238
  chainId,
145
- }: CreateNew1155Params & {
239
+ }: CreateNew1155TokenParams & {
146
240
  publicClient: Pick<PublicClient, "readContract">;
147
241
  chainId: number;
148
242
  }): Promise<CreateNew1155TokenReturn> {
149
- const { contractExists, contractAddress, nextTokenId, contractVersion } =
150
- await getContractInfo({
243
+ const { nextTokenId, contractVersion } =
244
+ await getContractInfoExistingContract({
151
245
  publicClient,
152
- chainId: chainId,
153
- contract,
154
- account,
246
+ contractAddress: contractAddress,
155
247
  });
156
248
 
157
249
  const {
158
250
  minter,
159
251
  newToken,
160
252
  setupActions: tokenSetupActions,
161
- } = constructCreate1155TokenCalls({
162
- chainId: chainId,
163
- ownerAddress: account,
253
+ } = await prepareSetupActions({
254
+ chainId,
255
+ account,
164
256
  contractVersion,
165
257
  nextTokenId,
166
- ...tokenConfig,
258
+ token,
259
+ getAdditionalSetupActions,
167
260
  });
168
261
 
169
- const setupActions = getAdditionalSetupActions
170
- ? [
171
- ...getAdditionalSetupActions({
172
- tokenId: nextTokenId,
173
- contractAddress,
174
- }),
175
- ...tokenSetupActions,
176
- ]
177
- : tokenSetupActions;
178
-
179
- const request = makeCreateContractAndTokenCall({
180
- contractExists,
262
+ const request = makeCreateTokenCall({
181
263
  contractAddress,
182
- contract,
183
264
  account,
184
- tokenSetupActions: setupActions,
185
- royaltyBPS: tokenConfig.royaltyBPS,
186
- fundsRecipient: tokenConfig.payoutRecipient,
265
+ tokenSetupActions,
187
266
  });
188
267
 
189
268
  return {
190
269
  parameters: request,
191
270
  tokenSetupActions,
192
- collectionAddress: contractAddress,
193
- contractExists,
194
271
  newTokenId: nextTokenId,
195
272
  newToken,
273
+ contractVersion,
196
274
  minter,
197
275
  };
198
276
  }
277
+
278
+ async function prepareSetupActions({
279
+ chainId,
280
+ account,
281
+ contractVersion,
282
+ nextTokenId,
283
+ token,
284
+ getAdditionalSetupActions,
285
+ }: {
286
+ chainId: number;
287
+ contractVersion: string;
288
+ nextTokenId: bigint;
289
+ } & CreateNew1155ParamsBase) {
290
+ const {
291
+ minter,
292
+ newToken,
293
+ setupActions: tokenSetupActions,
294
+ } = await constructCreate1155TokenCalls({
295
+ chainId: chainId,
296
+ ownerAddress: account,
297
+ contractVersion,
298
+ nextTokenId,
299
+ ...token,
300
+ });
301
+
302
+ const setupActions = getAdditionalSetupActions
303
+ ? [
304
+ ...getAdditionalSetupActions({
305
+ tokenId: nextTokenId,
306
+ }),
307
+ ...tokenSetupActions,
308
+ ]
309
+ : tokenSetupActions;
310
+
311
+ return { minter, newToken, setupActions };
312
+ }
@@ -1,14 +1,15 @@
1
- import { Address, PublicClient } from "viem";
2
- import { ContractType } from "./types";
1
+ import { Address, Hex, PublicClient } from "viem";
3
2
  import {
4
3
  contracts1155,
5
4
  zoraCreator1155FactoryImplABI,
6
5
  zoraCreator1155FactoryImplAddress,
7
6
  zoraCreator1155ImplABI,
8
7
  } from "@zoralabs/protocol-deployments";
8
+ import { NewContractParams } from "./types";
9
9
 
10
10
  type contracts1155Address = keyof typeof contracts1155.addresses;
11
- function new1155ContractVersion(chainId: number): string {
11
+ export function new1155ContractVersion(chainId: number): string {
12
+ // todo: get from subgraph
12
13
  const address = contracts1155.addresses[chainId as contracts1155Address];
13
14
  if (!address) {
14
15
  throw new Error(`No contract address for chainId ${chainId}`);
@@ -17,72 +18,81 @@ function new1155ContractVersion(chainId: number): string {
17
18
  return address.CONTRACT_1155_IMPL_VERSION;
18
19
  }
19
20
 
20
- export async function getContractInfo({
21
+ export async function getContractInfoExistingContract({
21
22
  publicClient,
22
- chainId,
23
- contract,
24
- account,
23
+ contractAddress,
25
24
  }: {
26
25
  publicClient: Pick<PublicClient, "readContract">;
27
- chainId: number;
28
- contract: ContractType;
26
+ contractAddress: Address;
29
27
  // Account that is the creator of the contract
30
- account: Address;
31
28
  }): Promise<{
32
- contractExists: boolean;
33
- contractAddress: Address;
34
29
  contractVersion: string;
30
+ contractName: string;
35
31
  nextTokenId: bigint;
36
32
  }> {
37
33
  // Check if contract exists either from metadata or the static address passed in.
38
34
  // If a static address is passed in, this fails if that contract does not exist.
39
- const contractAddress =
40
- typeof contract === "string"
41
- ? contract
42
- : await publicClient.readContract({
43
- abi: zoraCreator1155FactoryImplABI,
44
- // Since this address is deterministic we can hardcode a chain id safely here.
45
- address:
46
- zoraCreator1155FactoryImplAddress[
47
- chainId as keyof typeof zoraCreator1155FactoryImplAddress
48
- ],
49
- functionName: "deterministicContractAddress",
50
- args: [
51
- account,
52
- contract.uri,
53
- contract.name,
54
- contract.defaultAdmin || account,
55
- ],
56
- });
57
-
58
35
  let contractVersion: string;
59
- let contractExists: boolean;
60
36
  try {
61
37
  contractVersion = await publicClient.readContract({
62
38
  abi: zoraCreator1155ImplABI,
63
39
  address: contractAddress,
64
40
  functionName: "contractVersion",
65
41
  });
66
- contractExists = true;
67
42
  } catch (e: any) {
68
43
  // This logic branch is hit if the contract doesn't exist
69
44
  // falling back to contractExists to false.
70
- contractVersion = new1155ContractVersion(chainId);
71
- contractExists = false;
45
+ throw new Error(`Contract does not exist at ${contractAddress}`);
72
46
  }
73
47
 
74
- const nextTokenId = contractExists
75
- ? await publicClient.readContract({
76
- address: contractAddress,
77
- abi: zoraCreator1155ImplABI,
78
- functionName: "nextTokenId",
79
- })
80
- : 1n;
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
+ });
81
59
 
82
60
  return {
83
- contractExists,
84
- contractAddress,
85
61
  contractVersion,
62
+ contractName,
86
63
  nextTokenId,
87
64
  };
88
65
  }
66
+
67
+ export async function getDeterministicContractAddress({
68
+ publicClient,
69
+ account,
70
+ setupActions,
71
+ contract,
72
+ chainId,
73
+ }: {
74
+ account: Address;
75
+ publicClient: Pick<PublicClient, "readContract">;
76
+ setupActions: Hex[];
77
+ contract: NewContractParams;
78
+ chainId: number;
79
+ // Account that is the creator of the contract
80
+ }): Promise<Address> {
81
+ const contractAddress = await publicClient.readContract({
82
+ abi: zoraCreator1155FactoryImplABI,
83
+ address:
84
+ zoraCreator1155FactoryImplAddress[
85
+ chainId as keyof typeof zoraCreator1155FactoryImplAddress
86
+ ],
87
+ functionName: "deterministicContractAddressWithSetupActions",
88
+ args: [
89
+ account,
90
+ contract.uri,
91
+ contract.name,
92
+ contract.defaultAdmin || account,
93
+ setupActions,
94
+ ],
95
+ });
96
+
97
+ return contractAddress;
98
+ }
@@ -0,0 +1,21 @@
1
+ import { describe, it, expect, assert } from "vitest";
2
+ import { parseNameIntoSymbol } from "./minter-defaults";
3
+
4
+ describe("parseNameIntoSymbol", () => {
5
+ it("removes spaces and vowels and converts to uppercase", () => {
6
+ const symbol = parseNameIntoSymbol("My 4 To *5 @-Name");
7
+
8
+ expect(symbol).toBe("$MY4T");
9
+ });
10
+ it("works with less than 4 characters", () => {
11
+ const symbol = parseNameIntoSymbol("M4y a");
12
+
13
+ expect(symbol).toBe("$M4Y");
14
+ });
15
+
16
+ it("works with no characters", () => {
17
+ assert.throws(() => {
18
+ parseNameIntoSymbol("AEIO U");
19
+ }, "Not enough valid characters to generate a symbol");
20
+ });
21
+ });
@@ -0,0 +1,134 @@
1
+ import { Concrete } from "src/utils";
2
+ import {
3
+ SalesConfigParamsType,
4
+ AllowListParamType,
5
+ Erc20ParamsType,
6
+ FixedPriceParamsType,
7
+ SaleStartAndEnd,
8
+ MaxTokensPerAddress,
9
+ ConcreteSalesConfig,
10
+ TimedSaleParamsType,
11
+ } from "./types";
12
+ import { fetchTokenMetadata } from "src/ipfs/token-metadata";
13
+
14
+ // Sales end forever amount (uint64 max)
15
+ export const SALE_END_FOREVER = 18446744073709551615n;
16
+
17
+ const DEFAULT_SALE_START_AND_END: Concrete<SaleStartAndEnd> = {
18
+ // Sale start time – defaults to beginning of unix time
19
+ saleStart: 0n,
20
+ // This is the end of uint64, plenty of time
21
+ saleEnd: SALE_END_FOREVER,
22
+ };
23
+
24
+ const DEFAULT_MAX_TOKENS_PER_ADDRESS: Concrete<MaxTokensPerAddress> = {
25
+ maxTokensPerAddress: 0n,
26
+ };
27
+
28
+ const erc20SaleSettingsWithDefaults = (
29
+ params: Erc20ParamsType,
30
+ ): Concrete<Erc20ParamsType> => ({
31
+ ...DEFAULT_SALE_START_AND_END,
32
+ ...DEFAULT_MAX_TOKENS_PER_ADDRESS,
33
+ ...params,
34
+ });
35
+
36
+ const allowListWithDefaults = (
37
+ allowlist: AllowListParamType,
38
+ ): Concrete<AllowListParamType> => {
39
+ return {
40
+ ...DEFAULT_SALE_START_AND_END,
41
+ ...allowlist,
42
+ };
43
+ };
44
+
45
+ const fixedPriceSettingsWithDefaults = (
46
+ params: FixedPriceParamsType,
47
+ ): Concrete<FixedPriceParamsType> => ({
48
+ ...DEFAULT_SALE_START_AND_END,
49
+ ...DEFAULT_MAX_TOKENS_PER_ADDRESS,
50
+ type: "fixedPrice",
51
+ ...params,
52
+ });
53
+
54
+ export const parseNameIntoSymbol = (name: string) => {
55
+ if (name === "") {
56
+ throw new Error("Name must be provided to generate a symbol");
57
+ }
58
+ const result =
59
+ "$" +
60
+ name
61
+ // Remove all non-alphanumeric characters
62
+ .replace(/[^a-zA-Z0-9]/g, "")
63
+ // and leading dollar signs
64
+ .replace(/^\$+/, "")
65
+ .toUpperCase()
66
+ // Remove all vowels and spaces
67
+ .replace(/[AEIOU\s]/g, "")
68
+ // Strip down to 4 characters
69
+ .slice(0, 4);
70
+
71
+ if (result === "$") {
72
+ throw new Error("Not enough valid characters to generate a symbol");
73
+ }
74
+
75
+ return result;
76
+ };
77
+
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
+ const timedSaleSettingsWithDefaults = async (
90
+ params: TimedSaleParamsType,
91
+ tokenMetadataURI: string,
92
+ ): Promise<Concrete<TimedSaleParamsType>> => {
93
+ // If the name is not provided, try to fetch it from the metadata
94
+ const erc20Name =
95
+ params.erc20Name || (await fetchTokenNameFromMetadata(tokenMetadataURI));
96
+ const symbol = params.erc20Symbol || parseNameIntoSymbol(erc20Name);
97
+
98
+ return {
99
+ type: "timed",
100
+ ...DEFAULT_SALE_START_AND_END,
101
+ erc20Name,
102
+ erc20Symbol: symbol,
103
+ };
104
+ };
105
+
106
+ const isAllowList = (
107
+ salesConfig: SalesConfigParamsType,
108
+ ): salesConfig is AllowListParamType => salesConfig.type === "allowlistMint";
109
+ const isErc20 = (
110
+ salesConfig: SalesConfigParamsType,
111
+ ): salesConfig is Erc20ParamsType => salesConfig.type === "erc20Mint";
112
+ const isFixedPrice = (
113
+ salesConfig: SalesConfigParamsType,
114
+ ): salesConfig is FixedPriceParamsType => {
115
+ return (salesConfig as FixedPriceParamsType).pricePerToken > 0n;
116
+ };
117
+
118
+ export const getSalesConfigWithDefaults = async (
119
+ salesConfig: SalesConfigParamsType | undefined,
120
+ tokenMetadataURI: string,
121
+ ): Promise<ConcreteSalesConfig> => {
122
+ if (!salesConfig) return timedSaleSettingsWithDefaults({}, tokenMetadataURI);
123
+ if (isAllowList(salesConfig)) {
124
+ return allowListWithDefaults(salesConfig);
125
+ }
126
+ if (isErc20(salesConfig)) {
127
+ return erc20SaleSettingsWithDefaults(salesConfig);
128
+ }
129
+ if (isFixedPrice(salesConfig)) {
130
+ return fixedPriceSettingsWithDefaults(salesConfig);
131
+ }
132
+
133
+ return timedSaleSettingsWithDefaults(salesConfig, tokenMetadataURI);
134
+ };