@zoralabs/protocol-sdk 0.3.0 → 0.3.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.
@@ -3,7 +3,6 @@
3
3
  * Do not make direct changes to the file.
4
4
  */
5
5
 
6
-
7
6
  export interface paths {
8
7
  "/": {
9
8
  /** Root */
@@ -148,7 +147,19 @@ export interface components {
148
147
  * @description An enumeration.
149
148
  * @enum {string}
150
149
  */
151
- ChainName: "ETHEREUM-MAINNET" | "ETHEREUM-ROPSTEN" | "ETHEREUM-RINKEBY" | "ETHEREUM-GOERLI" | "ETHEREUM-SEPOLIA" | "OPTIMISM-MAINNET" | "OPTIMISM-GOERLI" | "ZORA-GOERLI" | "ZORA-MAINNET" | "BASE-MAINNET" | "BASE-GOERLI" | "PGN-MAINNET";
150
+ ChainName:
151
+ | "ETHEREUM-MAINNET"
152
+ | "ETHEREUM-ROPSTEN"
153
+ | "ETHEREUM-RINKEBY"
154
+ | "ETHEREUM-GOERLI"
155
+ | "ETHEREUM-SEPOLIA"
156
+ | "OPTIMISM-MAINNET"
157
+ | "OPTIMISM-GOERLI"
158
+ | "ZORA-GOERLI"
159
+ | "ZORA-MAINNET"
160
+ | "BASE-MAINNET"
161
+ | "BASE-GOERLI"
162
+ | "PGN-MAINNET";
152
163
  /** Collection */
153
164
  Collection: {
154
165
  /** Address */
@@ -395,7 +406,12 @@ export interface components {
395
406
  * @description An enumeration.
396
407
  * @enum {string}
397
408
  */
398
- FeedType: "curated" | "most_recent" | "heuristic" | "trending" | "recommendations";
409
+ FeedType:
410
+ | "curated"
411
+ | "most_recent"
412
+ | "heuristic"
413
+ | "trending"
414
+ | "recommendations";
399
415
  /**
400
416
  * FixedPrice
401
417
  * @description ObjectBase extends Pydantic's BaseModel class to support extra functionality
@@ -691,7 +707,13 @@ export interface components {
691
707
  /** Token Name */
692
708
  token_name?: string;
693
709
  /** Mint Context */
694
- mint_context?: components["schemas"]["ManifoldMintContext"] | components["schemas"]["ZoraCreateMintContext"] | components["schemas"]["FoundationMintContext"] | components["schemas"]["ZoraCreate1155MintContext"] | components["schemas"]["ZoraCreatePremintContext"] | components["schemas"]["InferredMintContext"];
710
+ mint_context?:
711
+ | components["schemas"]["ManifoldMintContext"]
712
+ | components["schemas"]["ZoraCreateMintContext"]
713
+ | components["schemas"]["FoundationMintContext"]
714
+ | components["schemas"]["ZoraCreate1155MintContext"]
715
+ | components["schemas"]["ZoraCreatePremintContext"]
716
+ | components["schemas"]["InferredMintContext"];
695
717
  /** Is Active */
696
718
  is_active: boolean;
697
719
  cost: components["schemas"]["zora__collect__feed__models__price_at_time__PriceAtTime"];
@@ -729,13 +751,30 @@ export interface components {
729
751
  * @description An enumeration.
730
752
  * @enum {string}
731
753
  */
732
- MintableStatus: "ACTIVE" | "BLOCKED" | "EXPIRED" | "INVALID_MEDIA" | "MINTED_OUT" | "DELETED";
754
+ MintableStatus:
755
+ | "ACTIVE"
756
+ | "BLOCKED"
757
+ | "EXPIRED"
758
+ | "INVALID_MEDIA"
759
+ | "MINTED_OUT"
760
+ | "DELETED";
733
761
  /**
734
762
  * MintableType
735
763
  * @description An enumeration.
736
764
  * @enum {string}
737
765
  */
738
- MintableType: "FOUNDATION_DROP_COLLECTION" | "FOUNDATION_TIMED_EDITION" | "MANIFOLD_ERC1155" | "MANIFOLD_ERC721" | "ZORA_CREATE" | "ZORA_CREATE_1155" | "ZORA_CREATE_1155_B2R_REDEEM_TOKEN" | "ZORA_CREATE_1155_PREMINT_TOKEN" | "ZORA_EDITION" | "ZORA_DROP" | "INFERRED";
766
+ MintableType:
767
+ | "FOUNDATION_DROP_COLLECTION"
768
+ | "FOUNDATION_TIMED_EDITION"
769
+ | "MANIFOLD_ERC1155"
770
+ | "MANIFOLD_ERC721"
771
+ | "ZORA_CREATE"
772
+ | "ZORA_CREATE_1155"
773
+ | "ZORA_CREATE_1155_B2R_REDEEM_TOKEN"
774
+ | "ZORA_CREATE_1155_PREMINT_TOKEN"
775
+ | "ZORA_EDITION"
776
+ | "ZORA_DROP"
777
+ | "INFERRED";
739
778
  /**
740
779
  * Network
741
780
  * @description An enumeration.
@@ -743,7 +782,9 @@ export interface components {
743
782
  */
744
783
  Network: "MAINNET" | "GOERLI";
745
784
  /** Notification */
746
- Notification: components["schemas"]["MintNotification"] | components["schemas"]["MintCommentNotification"];
785
+ Notification:
786
+ | components["schemas"]["MintNotification"]
787
+ | components["schemas"]["MintCommentNotification"];
747
788
  /**
748
789
  * NotificationsResponse
749
790
  * @description This is a generic model for pagination in an infitite scrolling context.
@@ -911,7 +952,9 @@ export interface components {
911
952
  description?: string;
912
953
  entity_type: components["schemas"]["EntityType"];
913
954
  /** Entity */
914
- entity: components["schemas"]["SearchCollection"] | components["schemas"]["SearchToken"];
955
+ entity:
956
+ | components["schemas"]["SearchCollection"]
957
+ | components["schemas"]["SearchToken"];
915
958
  media?: components["schemas"]["Media"];
916
959
  /**
917
960
  * Rank
@@ -1377,7 +1420,6 @@ export type $defs = Record<string, never>;
1377
1420
  export type external = Record<string, never>;
1378
1421
 
1379
1422
  export interface operations {
1380
-
1381
1423
  /** Root */
1382
1424
  root__get: {
1383
1425
  responses: {
@@ -3,7 +3,6 @@
3
3
  * Do not make direct changes to the file.
4
4
  */
5
5
 
6
-
7
6
  export interface paths {
8
7
  "/signature": {
9
8
  /** Upsert Premint Signature */
@@ -36,7 +35,19 @@ export interface components {
36
35
  * @description An enumeration.
37
36
  * @enum {string}
38
37
  */
39
- ChainName: "ETHEREUM-MAINNET" | "ETHEREUM-ROPSTEN" | "ETHEREUM-RINKEBY" | "ETHEREUM-GOERLI" | "ETHEREUM-SEPOLIA" | "OPTIMISM-MAINNET" | "OPTIMISM-GOERLI" | "ZORA-GOERLI" | "ZORA-MAINNET" | "BASE-MAINNET" | "BASE-GOERLI" | "PGN-MAINNET";
38
+ ChainName:
39
+ | "ETHEREUM-MAINNET"
40
+ | "ETHEREUM-ROPSTEN"
41
+ | "ETHEREUM-RINKEBY"
42
+ | "ETHEREUM-GOERLI"
43
+ | "ETHEREUM-SEPOLIA"
44
+ | "OPTIMISM-MAINNET"
45
+ | "OPTIMISM-GOERLI"
46
+ | "ZORA-GOERLI"
47
+ | "ZORA-MAINNET"
48
+ | "BASE-MAINNET"
49
+ | "BASE-GOERLI"
50
+ | "PGN-MAINNET";
40
51
  /**
41
52
  * CollectionCreationConfig
42
53
  * @description ObjectBase extends Pydantic's BaseModel class to support extra functionality
@@ -244,7 +255,6 @@ export type $defs = Record<string, never>;
244
255
  export type external = Record<string, never>;
245
256
 
246
257
  export interface operations {
247
-
248
258
  /** Upsert Premint Signature */
249
259
  upsert_premint_signature_signature_post: {
250
260
  requestBody: {
package/src/index.ts CHANGED
@@ -6,4 +6,6 @@ export * from "./premint/premint-api-client";
6
6
 
7
7
  export * from "./mint/mint-api-client";
8
8
 
9
+ export * from "./mint/mint-client";
10
+
9
11
  export * from "./create/1155-create-helper";
@@ -570,7 +570,7 @@ class PremintClient extends ClientBase {
570
570
  quantityToMint: number;
571
571
  mintComment?: string;
572
572
  };
573
- }): Promise<{request: SimulateContractParameters}> {
573
+ }): Promise<{ request: SimulateContractParameters }> {
574
574
  if (mintArguments && mintArguments?.quantityToMint < 1) {
575
575
  throw new Error("Quantity to mint cannot be below 1");
576
576
  }
@@ -1,4 +1,11 @@
1
- import { keccak256, Hex, concat, recoverAddress, hashDomain, Address } from "viem";
1
+ import {
2
+ keccak256,
3
+ Hex,
4
+ concat,
5
+ recoverAddress,
6
+ hashDomain,
7
+ Address,
8
+ } from "viem";
2
9
  import { foundry } from "viem/chains";
3
10
  import { describe, expect } from "vitest";
4
11
  import { parseEther } from "viem";
@@ -16,7 +23,12 @@ import {
16
23
  TokenCreationConfig,
17
24
  preminterTypedDataDefinition,
18
25
  } from "./preminter";
19
- import { AnvilViemClientsTest, anvilTest } from "src/anvil";
26
+ import {
27
+ AnvilViemClientsTest,
28
+ anvilTest,
29
+ forkUrls,
30
+ makeAnvilTest,
31
+ } from "src/anvil";
20
32
 
21
33
  // create token and contract creation config:
22
34
  const defaultContractConfig = ({
@@ -133,7 +145,10 @@ describe("ZoraCreator1155Preminter", () => {
133
145
  },
134
146
  20 * 1000,
135
147
  );
136
- anvilTest(
148
+ makeAnvilTest({
149
+ forkUrl: forkUrls.zoraGoerli,
150
+ forkBlockNumber: 1676105,
151
+ })(
137
152
  "can sign and recover a signature",
138
153
  async ({ viemClients }) => {
139
154
  const {
@@ -167,13 +182,15 @@ describe("ZoraCreator1155Preminter", () => {
167
182
  account: creatorAccount,
168
183
  });
169
184
 
185
+ const preminterAddress = zoraCreator1155PremintExecutorAddress[999];
170
186
  // recover and verify address is correct
171
- const recoveredAddress = await viemClients.publicClient.readContract({
172
- abi: preminterAbi,
173
- address: PREMINTER_ADDRESS,
174
- functionName: "recoverSigner",
175
- args: [premintConfig, contractAddress, signedMessage],
176
- });
187
+ const [, , recoveredAddress] =
188
+ await viemClients.publicClient.readContract({
189
+ abi: preminterAbi,
190
+ address: preminterAddress,
191
+ functionName: "isValidSignature",
192
+ args: [contractConfig, premintConfig, signedMessage],
193
+ });
177
194
 
178
195
  expect(recoveredAddress).to.equal(creatorAccount);
179
196
  },
@@ -279,6 +296,7 @@ describe("ZoraCreator1155Preminter", () => {
279
296
  args: [contractAddress, premintConfig.uid],
280
297
  });
281
298
 
299
+ expect(contractCreated).toBe(true);
282
300
  expect(tokenId).not.toBe(0n);
283
301
 
284
302
  // now use what was created, to get the balance from the created contract
@@ -0,0 +1,136 @@
1
+ import { Address } from "abitype";
2
+ import { ExtractAbiFunction, AbiParametersToPrimitiveTypes } from "abitype";
3
+ import {
4
+ zoraCreator1155PremintExecutorImplABI as preminterAbi,
5
+ zoraCreator1155PremintExecutorImplAddress,
6
+ } from "@zoralabs/protocol-deployments";
7
+ import {
8
+ TypedDataDefinition,
9
+ recoverTypedDataAddress,
10
+ Hex,
11
+ PublicClient,
12
+ } from "viem";
13
+
14
+ type PremintInputs = ExtractAbiFunction<
15
+ typeof preminterAbi,
16
+ "premint"
17
+ >["inputs"];
18
+
19
+ type PreminterHashDataTypes = AbiParametersToPrimitiveTypes<PremintInputs>;
20
+
21
+ export type ContractCreationConfig = PreminterHashDataTypes[0];
22
+ export type PremintConfig = PreminterHashDataTypes[1];
23
+ export type TokenCreationConfig = PremintConfig["tokenConfig"];
24
+
25
+ // Convenience method to create the structured typed data
26
+ // needed to sign for a premint contract and token
27
+ export const preminterTypedDataDefinition = ({
28
+ verifyingContract,
29
+ premintConfig,
30
+ chainId,
31
+ }: {
32
+ verifyingContract: Address;
33
+ premintConfig: PremintConfig;
34
+ chainId: number;
35
+ }) => {
36
+ const { tokenConfig, uid, version, deleted } = premintConfig;
37
+ const types = {
38
+ CreatorAttribution: [
39
+ { name: "tokenConfig", type: "TokenCreationConfig" },
40
+ // unique id scoped to the contract and token to create.
41
+ // ensure that a signature can be replaced, as long as the replacement
42
+ // has the same uid, and a newer version.
43
+ { name: "uid", type: "uint32" },
44
+ { name: "version", type: "uint32" },
45
+ // if this update should result in the signature being deleted.
46
+ { name: "deleted", type: "bool" },
47
+ ],
48
+ TokenCreationConfig: [
49
+ { name: "tokenURI", type: "string" },
50
+ { name: "maxSupply", type: "uint256" },
51
+ { name: "maxTokensPerAddress", type: "uint64" },
52
+ { name: "pricePerToken", type: "uint96" },
53
+ { name: "mintStart", type: "uint64" },
54
+ { name: "mintDuration", type: "uint64" },
55
+ { name: "royaltyMintSchedule", type: "uint32" },
56
+ { name: "royaltyBPS", type: "uint32" },
57
+ { name: "royaltyRecipient", type: "address" },
58
+ { name: "fixedPriceMinter", type: "address" },
59
+ ],
60
+ };
61
+
62
+ const result: TypedDataDefinition<typeof types, "CreatorAttribution"> = {
63
+ domain: {
64
+ chainId,
65
+ name: "Preminter",
66
+ version: "1",
67
+ verifyingContract: verifyingContract,
68
+ },
69
+ types,
70
+ message: {
71
+ tokenConfig,
72
+ uid,
73
+ version,
74
+ deleted,
75
+ },
76
+ primaryType: "CreatorAttribution",
77
+ };
78
+
79
+ return result;
80
+ };
81
+
82
+ export async function isValidSignatureV1({
83
+ contractAddress,
84
+ originalContractAdmin,
85
+ premintConfig,
86
+ signature,
87
+ chainId,
88
+ publicClient,
89
+ }: {
90
+ contractAddress: Address;
91
+ originalContractAdmin: Address;
92
+ premintConfig: PremintConfig;
93
+ signature: Hex;
94
+ chainId: number;
95
+ publicClient: PublicClient;
96
+ }): Promise<{
97
+ isAuthorized: boolean;
98
+ recoveredAddress?: Address;
99
+ }> {
100
+ const typedData = preminterTypedDataDefinition({
101
+ verifyingContract: contractAddress,
102
+ premintConfig,
103
+ chainId,
104
+ });
105
+
106
+ // recover the address from the signature
107
+ let recoveredAddress: Address;
108
+
109
+ try {
110
+ recoveredAddress = await recoverTypedDataAddress({
111
+ ...typedData,
112
+ signature,
113
+ });
114
+ } catch (error) {
115
+ console.error(error);
116
+
117
+ return {
118
+ isAuthorized: false,
119
+ };
120
+ }
121
+
122
+ // premint executor is same address on all chains
123
+ const premintExecutorAddress = zoraCreator1155PremintExecutorImplAddress[999];
124
+
125
+ const isAuthorized = await publicClient.readContract({
126
+ abi: preminterAbi,
127
+ address: premintExecutorAddress,
128
+ functionName: "isAuthorizedToCreatePremint",
129
+ args: [recoveredAddress, originalContractAdmin, contractAddress],
130
+ });
131
+
132
+ return {
133
+ isAuthorized,
134
+ recoveredAddress,
135
+ };
136
+ }