@zoralabs/protocol-sdk 0.2.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 (70) hide show
  1. package/.turbo/turbo-build.log +15 -0
  2. package/CHANGELOG.md +47 -0
  3. package/README.md +163 -0
  4. package/dist/anvil.d.ts +16 -0
  5. package/dist/anvil.d.ts.map +1 -0
  6. package/dist/apis/chain-constants.d.ts +21 -0
  7. package/dist/apis/chain-constants.d.ts.map +1 -0
  8. package/dist/apis/client-base.d.ts +15 -0
  9. package/dist/apis/client-base.d.ts.map +1 -0
  10. package/dist/apis/generated/discover-api-types.d.ts +2131 -0
  11. package/dist/apis/generated/discover-api-types.d.ts.map +1 -0
  12. package/dist/apis/generated/premint-api-types.d.ts +356 -0
  13. package/dist/apis/generated/premint-api-types.d.ts.map +1 -0
  14. package/dist/apis/http-api-base.d.ts +26 -0
  15. package/dist/apis/http-api-base.d.ts.map +1 -0
  16. package/dist/constants.d.ts +4 -0
  17. package/dist/constants.d.ts.map +1 -0
  18. package/dist/create/1155-create-helper.d.ts +63 -0
  19. package/dist/create/1155-create-helper.d.ts.map +1 -0
  20. package/dist/create/1155-create-helper.test.d.ts +2 -0
  21. package/dist/create/1155-create-helper.test.d.ts.map +1 -0
  22. package/dist/index.cjs +1006 -0
  23. package/dist/index.cjs.map +1 -0
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +984 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/mint/mint-api-client.d.ts +20 -0
  29. package/dist/mint/mint-api-client.d.ts.map +1 -0
  30. package/dist/mint/mint-client.d.ts +237 -0
  31. package/dist/mint/mint-client.d.ts.map +1 -0
  32. package/dist/mint/mint-client.test.d.ts +2 -0
  33. package/dist/mint/mint-client.test.d.ts.map +1 -0
  34. package/dist/premint/premint-api-client.d.ts +19 -0
  35. package/dist/premint/premint-api-client.d.ts.map +1 -0
  36. package/dist/premint/premint-client.d.ts +320 -0
  37. package/dist/premint/premint-client.d.ts.map +1 -0
  38. package/dist/premint/premint-client.test.d.ts +2 -0
  39. package/dist/premint/premint-client.test.d.ts.map +1 -0
  40. package/dist/premint/preminter.d.ts +25 -0
  41. package/dist/premint/preminter.d.ts.map +1 -0
  42. package/dist/premint/preminter.test.d.ts +2 -0
  43. package/dist/premint/preminter.test.d.ts.map +1 -0
  44. package/dist/preminter.d.ts +25 -0
  45. package/dist/preminter.d.ts.map +1 -0
  46. package/dist/preminter.test.d.ts +451 -0
  47. package/dist/preminter.test.d.ts.map +1 -0
  48. package/package.json +28 -0
  49. package/src/anvil.ts +84 -0
  50. package/src/apis/chain-constants.ts +101 -0
  51. package/src/apis/client-base.ts +29 -0
  52. package/src/apis/generated/discover-api-types.ts +2138 -0
  53. package/src/apis/generated/premint-api-types.ts +363 -0
  54. package/src/apis/http-api-base.ts +93 -0
  55. package/src/constants.ts +10 -0
  56. package/src/create/1155-create-helper.test.ts +90 -0
  57. package/src/create/1155-create-helper.ts +342 -0
  58. package/src/index.ts +9 -0
  59. package/src/mint/mint-api-client.ts +52 -0
  60. package/src/mint/mint-client.test.ts +117 -0
  61. package/src/mint/mint-client.ts +218 -0
  62. package/src/premint/premint-api-client.ts +57 -0
  63. package/src/premint/premint-client.test.ts +196 -0
  64. package/src/premint/premint-client.ts +619 -0
  65. package/src/premint/preminter.test.ts +502 -0
  66. package/src/premint/preminter.ts +72 -0
  67. package/src/preminter.test.ts +510 -0
  68. package/src/preminter.ts +72 -0
  69. package/tsconfig.json +25 -0
  70. package/tsup.config.js +10 -0
@@ -0,0 +1,218 @@
1
+ import {
2
+ Address,
3
+ Chain,
4
+ PublicClient,
5
+ encodeAbiParameters,
6
+ parseAbi,
7
+ parseAbiParameters,
8
+ zeroAddress,
9
+ } from "viem";
10
+ import { ClientBase } from "../apis/client-base";
11
+ import { MintAPIClient, MintableGetTokenResponse } from "./mint-api-client";
12
+ import { SimulateContractParameters } from "viem";
13
+ import {
14
+ zoraCreator1155ImplABI,
15
+ zoraCreatorFixedPriceSaleStrategyAddress,
16
+ } from "@zoralabs/protocol-deployments";
17
+
18
+ class MintError extends Error {}
19
+ class MintInactiveError extends Error {}
20
+
21
+ export const Errors = {
22
+ MintError,
23
+ MintInactiveError,
24
+ };
25
+
26
+ type MintArguments = {
27
+ quantityToMint: number;
28
+ mintComment?: string;
29
+ mintReferral?: Address;
30
+ mintToAddress: Address;
31
+ };
32
+
33
+ type MintParameters = {
34
+ mintArguments: MintArguments;
35
+ publicClient: PublicClient;
36
+ mintable: MintableGetTokenResponse;
37
+ sender: Address;
38
+ };
39
+
40
+ const zora721Abi = parseAbi([
41
+ "function mintWithRewards(address recipient, uint256 quantity, string calldata comment, address mintReferral) external payable",
42
+ "function zoraFeeForAmount(uint256 amount) public view returns (address, uint256)",
43
+ ] as const);
44
+
45
+ export class MintClient extends ClientBase {
46
+ apiClient: typeof MintAPIClient;
47
+
48
+ constructor(chain: Chain, apiClient?: typeof MintAPIClient) {
49
+ super(chain);
50
+
51
+ if (!apiClient) {
52
+ apiClient = MintAPIClient;
53
+ }
54
+ this.apiClient = apiClient;
55
+ }
56
+
57
+ async getMintable({
58
+ tokenContract,
59
+ tokenId,
60
+ }: {
61
+ tokenContract: Address;
62
+ tokenId?: bigint | number | string;
63
+ }) {
64
+ return this.apiClient.getMintable(
65
+ {
66
+ chain_name: this.network.zoraBackendChainName,
67
+ collection_address: tokenContract,
68
+ },
69
+ { token_id: tokenId?.toString() },
70
+ );
71
+ }
72
+
73
+ async makePrepareMintTokenParams({
74
+ publicClient,
75
+ minterAccount,
76
+ mintable,
77
+ mintArguments,
78
+ }: {
79
+ publicClient: PublicClient;
80
+ mintable: MintableGetTokenResponse;
81
+ minterAccount: Address;
82
+ mintArguments: MintArguments;
83
+ }): Promise<{simulateContractParameters: SimulateContractParameters}> {
84
+ if (!mintable) {
85
+ throw new MintError("No mintable found");
86
+ }
87
+
88
+ if (!mintable.is_active) {
89
+ throw new MintInactiveError("Minting token is inactive");
90
+ }
91
+
92
+ if (!mintable.mint_context) {
93
+ throw new MintError("No minting context data from zora API");
94
+ }
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
+ );
104
+ }
105
+
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
+ }
128
+
129
+ throw new Error("Mintable type not found or recognized.");
130
+ }
131
+
132
+ private async prepareMintZora1155({
133
+ mintable,
134
+ sender,
135
+ publicClient,
136
+ mintArguments,
137
+ }: MintParameters) {
138
+ const mintQuantity = BigInt(mintArguments.quantityToMint);
139
+
140
+ const address = mintable.collection.address as Address;
141
+
142
+ const mintFee = await publicClient.readContract({
143
+ abi: zoraCreator1155ImplABI,
144
+ functionName: "mintFee",
145
+ address,
146
+ });
147
+
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
+ );
155
+
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;
180
+ }
181
+
182
+ private async prepareMintZora721({
183
+ mintable,
184
+ 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
+ });
194
+
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
+ };
215
+
216
+ return result;
217
+ }
218
+ }
@@ -0,0 +1,57 @@
1
+ import { post, retries, get } from "../apis/http-api-base";
2
+ import { components, paths } from "../apis/generated/premint-api-types";
3
+ import { ZORA_API_BASE } from "../constants";
4
+
5
+ type SignaturePostType = paths["/signature"]["post"];
6
+ type PremintSignatureRequestBody =
7
+ SignaturePostType["requestBody"]["content"]["application/json"];
8
+ export type PremintSignatureResponse =
9
+ SignaturePostType["responses"][200]["content"]["application/json"];
10
+
11
+ type PremintNextUIDGetType =
12
+ paths["/signature/{chain_name}/{collection_address}/next_uid"]["get"];
13
+ type PremintNextUIDGetPathParameters =
14
+ PremintNextUIDGetType["parameters"]["path"];
15
+ export type PremintNextUIDGetResponse =
16
+ PremintNextUIDGetType["responses"][200]["content"]["application/json"];
17
+
18
+ type SignaturePremintGetType =
19
+ paths["/signature/{chain_name}/{collection_address}/{uid}"]["get"];
20
+ type PremintSignatureGetPathParameters =
21
+ SignaturePremintGetType["parameters"]["path"];
22
+ export type PremintSignatureGetResponse =
23
+ SignaturePremintGetType["responses"][200]["content"]["application/json"];
24
+
25
+ export type BackendChainNames = components["schemas"]["ChainName"];
26
+
27
+ const postSignature = async (
28
+ data: PremintSignatureRequestBody,
29
+ ): Promise<PremintSignatureResponse> =>
30
+ retries(() =>
31
+ post<PremintSignatureResponse>(`${ZORA_API_BASE}premint/signature`, data),
32
+ );
33
+
34
+ const getNextUID = async (
35
+ path: PremintNextUIDGetPathParameters,
36
+ ): Promise<PremintNextUIDGetResponse> =>
37
+ retries(() =>
38
+ get<PremintNextUIDGetResponse>(
39
+ `${ZORA_API_BASE}premint/signature/${path.chain_name}/${path.collection_address}/next_uid`,
40
+ ),
41
+ );
42
+
43
+ const getSignature = async (
44
+ path: PremintSignatureGetPathParameters,
45
+ ): Promise<PremintSignatureGetResponse> =>
46
+ retries(() =>
47
+ get<PremintSignatureGetResponse>(
48
+ `${ZORA_API_BASE}premint/signature/${path.chain_name}/${path.collection_address}/${path.uid}`,
49
+ ),
50
+ );
51
+
52
+ export const PremintAPIClient = {
53
+ postSignature,
54
+ getSignature,
55
+ getNextUID,
56
+ };
57
+ export { ZORA_API_BASE };
@@ -0,0 +1,196 @@
1
+ import { foundry } from "viem/chains";
2
+ import { describe, expect, vi } from "vitest";
3
+ import { PremintClient } from "./premint-client";
4
+ import { anvilTest } from "src/anvil";
5
+ import { BackendChainNamesLookup } from "src/apis/chain-constants";
6
+
7
+ describe("ZoraCreator1155Premint", () => {
8
+ anvilTest(
9
+ "can sign on the forked premint contract",
10
+ async ({ viemClients: { walletClient, publicClient } }) => {
11
+ const [deployerAccount] = await walletClient.getAddresses();
12
+ const premintClient = new PremintClient(foundry);
13
+
14
+ premintClient.apiClient.getNextUID = vi
15
+ .fn()
16
+ .mockResolvedValue({ next_uid: 3 });
17
+ premintClient.apiClient.postSignature = vi
18
+ .fn()
19
+ .mockResolvedValue({ ok: true });
20
+
21
+ await premintClient.createPremint({
22
+ walletClient,
23
+ publicClient,
24
+ account: deployerAccount!,
25
+ checkSignature: true,
26
+ collection: {
27
+ contractAdmin: deployerAccount!,
28
+ contractName: "Testing Contract",
29
+ contractURI:
30
+ "ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
31
+ },
32
+ token: {
33
+ tokenURI:
34
+ "ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
35
+ },
36
+ });
37
+
38
+ expect(premintClient.apiClient.postSignature).toHaveBeenCalledWith({
39
+ chain_name: BackendChainNamesLookup.ZORA_GOERLI,
40
+ collection: {
41
+ contractAdmin: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
42
+ contractName: "Testing Contract",
43
+ contractURI:
44
+ "ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
45
+ },
46
+ premint: {
47
+ deleted: false,
48
+ tokenConfig: {
49
+ fixedPriceMinter: "0x04E2516A2c207E84a1839755675dfd8eF6302F0a",
50
+ maxSupply: "18446744073709551615",
51
+ maxTokensPerAddress: "0",
52
+ mintDuration: "604800",
53
+ mintStart: "0",
54
+ pricePerToken: "0",
55
+ royaltyBPS: 1000,
56
+ royaltyMintSchedule: 0,
57
+ royaltyRecipient: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
58
+ tokenURI:
59
+ "ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
60
+ },
61
+ uid: 3,
62
+ version: 1,
63
+ },
64
+ signature:
65
+ "0x588d19641de9ba1dade4d2bb5387c8dc96f4a990fef69787534b60caead759e6334975a6be10a796da948cd7d1d4f5580b3f84d49d9fa4e0b41c97759507975a1c",
66
+ });
67
+ },
68
+ 20 * 1000,
69
+ );
70
+
71
+ anvilTest(
72
+ "can validate premint on network",
73
+ async ({ viemClients: { publicClient } }) => {
74
+ const premintClient = new PremintClient(foundry);
75
+
76
+ const premintData = {
77
+ collection: {
78
+ contractAdmin: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
79
+ contractName: "Testing Contract",
80
+ contractURI:
81
+ "ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
82
+ },
83
+ premint: {
84
+ uid: 3,
85
+ version: 1,
86
+ deleted: false,
87
+ tokenConfig: {
88
+ maxSupply: "18446744073709551615",
89
+ maxTokensPerAddress: "0",
90
+ pricePerToken: "0",
91
+ mintDuration: "604800",
92
+ mintStart: "0",
93
+ royaltyMintSchedule: 0,
94
+ royaltyBPS: 1000,
95
+ fixedPriceMinter: "0x04E2516A2c207E84a1839755675dfd8eF6302F0a",
96
+ royaltyRecipient: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
97
+ tokenURI:
98
+ "ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
99
+ },
100
+ },
101
+ chain_name: "ZORA-TESTNET",
102
+ signature:
103
+ "0x588d19641de9ba1dade4d2bb5387c8dc96f4a990fef69787534b60caead759e6334975a6be10a796da948cd7d1d4f5580b3f84d49d9fa4e0b41c97759507975a1c",
104
+ } as const;
105
+
106
+ const signatureValid = await premintClient.isValidSignature({
107
+ // @ts-ignore: Fix enum type
108
+ data: premintData,
109
+ publicClient,
110
+ });
111
+ expect(signatureValid.isValid).toBe(true);
112
+ },
113
+ );
114
+
115
+ anvilTest(
116
+ "can execute premint on network",
117
+ async ({ viemClients: { walletClient, publicClient } }) => {
118
+ const [deployerAccount] = await walletClient.getAddresses();
119
+ const premintClient = new PremintClient(foundry);
120
+
121
+ premintClient.apiClient.getSignature = vi.fn().mockResolvedValue({
122
+ chain_name: "ZORA-TESTNET",
123
+ collection: {
124
+ contractAdmin: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
125
+ contractName: "Testing Contract",
126
+ contractURI:
127
+ "ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
128
+ },
129
+ premint: {
130
+ deleted: false,
131
+ tokenConfig: {
132
+ fixedPriceMinter: "0x04E2516A2c207E84a1839755675dfd8eF6302F0a",
133
+ maxSupply: "18446744073709551615",
134
+ maxTokensPerAddress: "0",
135
+ mintDuration: "604800",
136
+ mintStart: "0",
137
+ pricePerToken: "0",
138
+ royaltyBPS: 1000,
139
+ royaltyMintSchedule: 0,
140
+ royaltyRecipient: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
141
+ tokenURI:
142
+ "ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
143
+ },
144
+ uid: 3,
145
+ version: 1,
146
+ },
147
+ signature:
148
+ "0x588d19641de9ba1dade4d2bb5387c8dc96f4a990fef69787534b60caead759e6334975a6be10a796da948cd7d1d4f5580b3f84d49d9fa4e0b41c97759507975a1c",
149
+ });
150
+ premintClient.apiClient.postSignature = vi.fn();
151
+
152
+ const premint = await premintClient.executePremintWithWallet({
153
+ data: await premintClient.getPremintData({
154
+ address: "0xf8dA7f53c283d898818af7FB9d98103F559bDac2",
155
+ uid: 3,
156
+ }),
157
+ account: deployerAccount,
158
+ walletClient,
159
+ publicClient,
160
+ mintArguments: {
161
+ quantityToMint: 1,
162
+ mintComment: "",
163
+ },
164
+ });
165
+
166
+ expect(premint.premintedLog).toEqual({
167
+ contractAddress: "0xf8dA7f53c283d898818af7FB9d98103F559bDac2",
168
+ contractConfig: {
169
+ contractAdmin: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
170
+ contractName: "Testing Contract",
171
+ contractURI:
172
+ "ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
173
+ },
174
+ createdNewContract: expect.any(Boolean),
175
+ minter: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
176
+ quantityMinted: 1n,
177
+ tokenConfig: {
178
+ fixedPriceMinter: "0x04E2516A2c207E84a1839755675dfd8eF6302F0a",
179
+ maxSupply: 18446744073709551615n,
180
+ maxTokensPerAddress: 0n,
181
+ mintDuration: 604800n,
182
+ mintStart: 0n,
183
+ pricePerToken: 0n,
184
+ royaltyBPS: 1000,
185
+ royaltyMintSchedule: 0,
186
+ royaltyRecipient: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
187
+ tokenURI:
188
+ "ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
189
+ },
190
+ tokenId: 1n,
191
+ uid: 3,
192
+ });
193
+ },
194
+ 20 * 1000,
195
+ );
196
+ });