@zoralabs/protocol-sdk 0.5.6-exports.0 → 0.5.6
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.
- package/.turbo/turbo-build.log +16 -0
- package/CHANGELOG.md +4 -4
- package/package.json +2 -2
- package/src/create/1155-create-helper.test.ts +104 -0
- package/src/mint/mint-client.test.ts +114 -0
- package/src/premint/premint-client.test.ts +239 -0
- package/src/premint/preminter.test.ts +615 -0
- package/test-integration/premint-client.test.ts +146 -0
- package/tsconfig.build.json +10 -0
- package/tsup.config.ts +12 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
warning package.json: "dependencies" has dependency "vite" with range "4.5.0" that collides with a dependency in "devDependencies" of the same name with version "^4.5.0"
|
|
2
|
+
$ tsup
|
|
3
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
4
|
+
[34mCLI[39m Using tsconfig: tsconfig.build.json
|
|
5
|
+
[34mCLI[39m tsup v7.3.0
|
|
6
|
+
[34mCLI[39m Using tsup config: /home/runner/work/zora-protocol-private/zora-protocol-private/packages/protocol-sdk/tsup.config.ts
|
|
7
|
+
[34mCLI[39m Target: es2021
|
|
8
|
+
[34mCLI[39m Cleaning output folder
|
|
9
|
+
[34mCJS[39m Build start
|
|
10
|
+
[34mESM[39m Build start
|
|
11
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m50.17 KB[39m
|
|
12
|
+
[32mCJS[39m [1mdist/index.cjs.map [22m[32m97.10 KB[39m
|
|
13
|
+
[32mCJS[39m ⚡️ Build success in 72ms
|
|
14
|
+
[32mESM[39m [1mdist/index.js [22m[32m46.25 KB[39m
|
|
15
|
+
[32mESM[39m [1mdist/index.js.map [22m[32m97.16 KB[39m
|
|
16
|
+
[32mESM[39m ⚡️ Build success in 72ms
|
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# @zoralabs/protocol-sdk
|
|
2
2
|
|
|
3
|
-
## 0.5.6
|
|
3
|
+
## 0.5.6
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
- Updated dependencies [
|
|
9
|
-
- @zoralabs/protocol-deployments@0.1.2
|
|
7
|
+
- 52b16aa: Publishing package in format that supports commonjs imports by specifying exports
|
|
8
|
+
- Updated dependencies [52b16aa]
|
|
9
|
+
- @zoralabs/protocol-deployments@0.1.2
|
|
10
10
|
|
|
11
11
|
## 0.5.5
|
|
12
12
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zoralabs/protocol-sdk",
|
|
3
|
-
"version": "0.5.6
|
|
3
|
+
"version": "0.5.6",
|
|
4
4
|
"repository": "https://github.com/ourzora/zora-protocol",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"lint": "prettier --check 'src/**/*.ts' 'test-integration/**/*.ts'"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@zoralabs/protocol-deployments": "
|
|
28
|
+
"@zoralabs/protocol-deployments": "*",
|
|
29
29
|
"abitype": "^0.10.3",
|
|
30
30
|
"vite": "4.5.0"
|
|
31
31
|
},
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { parseEther } from "viem";
|
|
2
|
+
import { describe, expect } from "vitest";
|
|
3
|
+
import {
|
|
4
|
+
create1155CreatorClient,
|
|
5
|
+
getTokenIdFromCreateReceipt,
|
|
6
|
+
} from "./1155-create-helper";
|
|
7
|
+
import { anvilTest } from "src/anvil";
|
|
8
|
+
|
|
9
|
+
const demoTokenMetadataURI = "ipfs://DUMMY/token.json";
|
|
10
|
+
const demoContractMetadataURI = "ipfs://DUMMY/contract.json";
|
|
11
|
+
|
|
12
|
+
describe("create-helper", () => {
|
|
13
|
+
anvilTest(
|
|
14
|
+
"creates a new contract given arguments",
|
|
15
|
+
async ({ viemClients: { testClient, publicClient, walletClient } }) => {
|
|
16
|
+
const addresses = await walletClient.getAddresses();
|
|
17
|
+
const creatorAddress = addresses[0]!;
|
|
18
|
+
await testClient.setBalance({
|
|
19
|
+
address: creatorAddress,
|
|
20
|
+
value: parseEther("1"),
|
|
21
|
+
});
|
|
22
|
+
const creatorClient = create1155CreatorClient({
|
|
23
|
+
publicClient: publicClient,
|
|
24
|
+
});
|
|
25
|
+
const { request } = await creatorClient.createNew1155Token({
|
|
26
|
+
contract: {
|
|
27
|
+
name: "testContract",
|
|
28
|
+
uri: demoContractMetadataURI,
|
|
29
|
+
},
|
|
30
|
+
tokenMetadataURI: demoTokenMetadataURI,
|
|
31
|
+
account: creatorAddress,
|
|
32
|
+
mintToCreatorCount: 1,
|
|
33
|
+
});
|
|
34
|
+
const { request: simulationResponse } =
|
|
35
|
+
await publicClient.simulateContract(request);
|
|
36
|
+
const hash = await walletClient.writeContract(simulationResponse);
|
|
37
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
38
|
+
expect(receipt).not.toBeNull();
|
|
39
|
+
expect(receipt.to).to.equal("0x777777c338d93e2c7adf08d102d45ca7cc4ed021");
|
|
40
|
+
expect(getTokenIdFromCreateReceipt(receipt)).to.be.equal(1n);
|
|
41
|
+
},
|
|
42
|
+
20 * 1000,
|
|
43
|
+
);
|
|
44
|
+
anvilTest(
|
|
45
|
+
"creates a new contract, than creates a new token on this existing contract",
|
|
46
|
+
async ({ viemClients: { publicClient, walletClient } }) => {
|
|
47
|
+
const addresses = await walletClient.getAddresses();
|
|
48
|
+
const creatorAccount = addresses[0]!;
|
|
49
|
+
|
|
50
|
+
const creatorClient = create1155CreatorClient({
|
|
51
|
+
publicClient: publicClient,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const { request, contractAddress, contractExists } =
|
|
55
|
+
await creatorClient.createNew1155Token({
|
|
56
|
+
contract: {
|
|
57
|
+
name: "testContract2",
|
|
58
|
+
uri: demoContractMetadataURI,
|
|
59
|
+
},
|
|
60
|
+
tokenMetadataURI: demoTokenMetadataURI,
|
|
61
|
+
account: creatorAccount,
|
|
62
|
+
mintToCreatorCount: 1,
|
|
63
|
+
});
|
|
64
|
+
expect(contractAddress).to.be.equal(
|
|
65
|
+
"0xb1A8928dF830C21eD682949Aa8A83C1C215194d3",
|
|
66
|
+
);
|
|
67
|
+
expect(contractExists).to.be.false;
|
|
68
|
+
const { request: simulateResponse } =
|
|
69
|
+
await publicClient.simulateContract(request);
|
|
70
|
+
const hash = await walletClient.writeContract(simulateResponse);
|
|
71
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
72
|
+
const firstTokenId = getTokenIdFromCreateReceipt(receipt);
|
|
73
|
+
expect(firstTokenId).to.be.equal(1n);
|
|
74
|
+
expect(receipt).not.toBeNull();
|
|
75
|
+
|
|
76
|
+
const newTokenOnExistingContract = await creatorClient.createNew1155Token(
|
|
77
|
+
{
|
|
78
|
+
contract: {
|
|
79
|
+
name: "testContract2",
|
|
80
|
+
uri: demoContractMetadataURI,
|
|
81
|
+
},
|
|
82
|
+
tokenMetadataURI: demoTokenMetadataURI,
|
|
83
|
+
account: creatorAccount,
|
|
84
|
+
mintToCreatorCount: 1,
|
|
85
|
+
},
|
|
86
|
+
);
|
|
87
|
+
expect(newTokenOnExistingContract.contractAddress).to.be.equal(
|
|
88
|
+
"0xb1A8928dF830C21eD682949Aa8A83C1C215194d3",
|
|
89
|
+
);
|
|
90
|
+
expect(newTokenOnExistingContract.contractExists).to.be.true;
|
|
91
|
+
const { request: simulateRequest } = await publicClient.simulateContract(
|
|
92
|
+
newTokenOnExistingContract.request,
|
|
93
|
+
);
|
|
94
|
+
const newHash = await walletClient.writeContract(simulateRequest);
|
|
95
|
+
const newReceipt = await publicClient.waitForTransactionReceipt({
|
|
96
|
+
hash: newHash,
|
|
97
|
+
});
|
|
98
|
+
const tokenId = getTokenIdFromCreateReceipt(newReceipt);
|
|
99
|
+
expect(tokenId).to.be.equal(2n);
|
|
100
|
+
expect(newReceipt).not.toBeNull();
|
|
101
|
+
},
|
|
102
|
+
20 * 1000,
|
|
103
|
+
);
|
|
104
|
+
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Address, parseAbi, parseEther } from "viem";
|
|
2
|
+
import { zora } from "viem/chains";
|
|
3
|
+
import { describe, expect } from "vitest";
|
|
4
|
+
import { createMintClient } from "./mint-client";
|
|
5
|
+
import { zoraCreator1155ImplABI } from "@zoralabs/protocol-deployments";
|
|
6
|
+
import { anvilTest, forkUrls, makeAnvilTest } from "src/anvil";
|
|
7
|
+
|
|
8
|
+
const erc721ABI = parseAbi([
|
|
9
|
+
"function balanceOf(address owner) public view returns (uint256)",
|
|
10
|
+
] as const);
|
|
11
|
+
|
|
12
|
+
describe("mint-helper", () => {
|
|
13
|
+
anvilTest(
|
|
14
|
+
"mints a new 1155 token",
|
|
15
|
+
async ({ viemClients }) => {
|
|
16
|
+
const { testClient, walletClient, publicClient } = viemClients;
|
|
17
|
+
const creatorAccount = (await walletClient.getAddresses())[0]!;
|
|
18
|
+
await testClient.setBalance({
|
|
19
|
+
address: creatorAccount,
|
|
20
|
+
value: parseEther("2000"),
|
|
21
|
+
});
|
|
22
|
+
const targetContract: Address =
|
|
23
|
+
"0xa2fea3537915dc6c7c7a97a82d1236041e6feb2e";
|
|
24
|
+
const targetTokenId = 1n;
|
|
25
|
+
const minter = createMintClient({ chain: zora });
|
|
26
|
+
|
|
27
|
+
const params = await minter.makePrepareMintTokenParams({
|
|
28
|
+
minterAccount: creatorAccount,
|
|
29
|
+
tokenId: targetTokenId,
|
|
30
|
+
tokenAddress: targetContract,
|
|
31
|
+
mintArguments: {
|
|
32
|
+
mintToAddress: creatorAccount,
|
|
33
|
+
quantityToMint: 1,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const oldBalance = await publicClient.readContract({
|
|
38
|
+
abi: zoraCreator1155ImplABI,
|
|
39
|
+
address: targetContract,
|
|
40
|
+
functionName: "balanceOf",
|
|
41
|
+
args: [creatorAccount, targetTokenId],
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const simulationResult = await publicClient.simulateContract(params);
|
|
45
|
+
|
|
46
|
+
const hash = await walletClient.writeContract(simulationResult.request);
|
|
47
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
48
|
+
const newBalance = await publicClient.readContract({
|
|
49
|
+
abi: zoraCreator1155ImplABI,
|
|
50
|
+
address: targetContract,
|
|
51
|
+
functionName: "balanceOf",
|
|
52
|
+
args: [creatorAccount, targetTokenId],
|
|
53
|
+
});
|
|
54
|
+
expect(receipt).to.not.be.null;
|
|
55
|
+
expect(oldBalance).to.be.equal(0n);
|
|
56
|
+
expect(newBalance).to.be.equal(1n);
|
|
57
|
+
},
|
|
58
|
+
12 * 1000,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
makeAnvilTest({
|
|
62
|
+
forkUrl: forkUrls.zoraMainnet,
|
|
63
|
+
forkBlockNumber: 6133407,
|
|
64
|
+
})(
|
|
65
|
+
"mints a new 721 token",
|
|
66
|
+
async ({ viemClients }) => {
|
|
67
|
+
const { testClient, walletClient, publicClient } = viemClients;
|
|
68
|
+
const creatorAccount = (await walletClient.getAddresses())[0]!;
|
|
69
|
+
await testClient.setBalance({
|
|
70
|
+
address: creatorAccount,
|
|
71
|
+
value: parseEther("2000"),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const targetContract: Address =
|
|
75
|
+
"0x7aae7e67515A2CbB8585C707Ca6db37BDd3EA839";
|
|
76
|
+
const targetTokenId = undefined;
|
|
77
|
+
const minter = createMintClient({ chain: zora });
|
|
78
|
+
|
|
79
|
+
const params = await minter.makePrepareMintTokenParams({
|
|
80
|
+
tokenId: targetTokenId,
|
|
81
|
+
tokenAddress: targetContract,
|
|
82
|
+
minterAccount: creatorAccount,
|
|
83
|
+
mintArguments: {
|
|
84
|
+
mintToAddress: creatorAccount,
|
|
85
|
+
quantityToMint: 1,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
const oldBalance = await publicClient.readContract({
|
|
89
|
+
abi: erc721ABI,
|
|
90
|
+
address: targetContract,
|
|
91
|
+
functionName: "balanceOf",
|
|
92
|
+
args: [creatorAccount],
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const simulated = await publicClient.simulateContract(params);
|
|
96
|
+
|
|
97
|
+
const hash = await walletClient.writeContract(simulated.request);
|
|
98
|
+
|
|
99
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
100
|
+
expect(receipt).not.to.be.null;
|
|
101
|
+
|
|
102
|
+
const newBalance = await publicClient.readContract({
|
|
103
|
+
abi: erc721ABI,
|
|
104
|
+
address: targetContract,
|
|
105
|
+
functionName: "balanceOf",
|
|
106
|
+
args: [creatorAccount],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(oldBalance).to.be.equal(0n);
|
|
110
|
+
expect(newBalance).to.be.equal(1n);
|
|
111
|
+
},
|
|
112
|
+
12 * 1000,
|
|
113
|
+
);
|
|
114
|
+
});
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { foundry } from "viem/chains";
|
|
2
|
+
import { describe, expect, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { createPremintClient } from "./premint-client";
|
|
5
|
+
import { anvilTest } from "src/anvil";
|
|
6
|
+
import { PremintConfigVersion } from "./contract-types";
|
|
7
|
+
import { getDefaultFixedPriceMinterAddress } from "./preminter";
|
|
8
|
+
|
|
9
|
+
describe("ZoraCreator1155Premint - v1 signatures", () => {
|
|
10
|
+
anvilTest(
|
|
11
|
+
"can sign by default v1 on the forked premint contract",
|
|
12
|
+
async ({ viemClients: { walletClient, publicClient, chain } }) => {
|
|
13
|
+
const [deployerAccount] = await walletClient.getAddresses();
|
|
14
|
+
const premintClient = createPremintClient({
|
|
15
|
+
chain,
|
|
16
|
+
publicClient,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
premintClient.apiClient.getNextUID = vi
|
|
20
|
+
.fn<any, ReturnType<typeof premintClient.apiClient.getNextUID>>()
|
|
21
|
+
.mockResolvedValue(3);
|
|
22
|
+
premintClient.apiClient.postSignature = vi
|
|
23
|
+
.fn<Parameters<typeof premintClient.apiClient.postSignature>>()
|
|
24
|
+
.mockResolvedValue({ ok: true });
|
|
25
|
+
|
|
26
|
+
await premintClient.createPremint({
|
|
27
|
+
walletClient,
|
|
28
|
+
creatorAccount: deployerAccount!,
|
|
29
|
+
checkSignature: true,
|
|
30
|
+
collection: {
|
|
31
|
+
contractAdmin: deployerAccount!,
|
|
32
|
+
contractName: "Testing Contract",
|
|
33
|
+
contractURI:
|
|
34
|
+
"ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
|
|
35
|
+
},
|
|
36
|
+
tokenCreationConfig: {
|
|
37
|
+
tokenURI:
|
|
38
|
+
"ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const expectedPostSignatureArgs: Parameters<
|
|
43
|
+
typeof premintClient.apiClient.postSignature
|
|
44
|
+
>[0] = {
|
|
45
|
+
collection: {
|
|
46
|
+
contractAdmin: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
47
|
+
contractName: "Testing Contract",
|
|
48
|
+
contractURI:
|
|
49
|
+
"ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
|
|
50
|
+
},
|
|
51
|
+
premintConfig: {
|
|
52
|
+
deleted: false,
|
|
53
|
+
tokenConfig: {
|
|
54
|
+
fixedPriceMinter: getDefaultFixedPriceMinterAddress(chain.id),
|
|
55
|
+
maxSupply: 18446744073709551615n,
|
|
56
|
+
maxTokensPerAddress: 0n,
|
|
57
|
+
mintDuration: 604800n,
|
|
58
|
+
mintStart: 0n,
|
|
59
|
+
pricePerToken: 0n,
|
|
60
|
+
royaltyBPS: 1000,
|
|
61
|
+
royaltyMintSchedule: 0,
|
|
62
|
+
royaltyRecipient: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
63
|
+
tokenURI:
|
|
64
|
+
"ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
|
|
65
|
+
},
|
|
66
|
+
uid: 3,
|
|
67
|
+
version: 0,
|
|
68
|
+
},
|
|
69
|
+
premintConfigVersion: PremintConfigVersion.V1,
|
|
70
|
+
signature:
|
|
71
|
+
"0x70fc1d6e862c42f2b0e4a062f4eb973cc8692df58a24b71b4fe91ae7baa5a26d2c99b1b8ab61f64ff431bf30b0897877b11b7405542c90b89b041808f1561a6c1c",
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
expect(premintClient.apiClient.postSignature).toHaveBeenCalledWith(
|
|
75
|
+
expectedPostSignatureArgs,
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
20 * 1000,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
anvilTest(
|
|
82
|
+
"can execute premint on network",
|
|
83
|
+
async ({ viemClients: { walletClient, publicClient, chain } }) => {
|
|
84
|
+
const [deployerAccount] = await walletClient.getAddresses();
|
|
85
|
+
const premintClient = createPremintClient({
|
|
86
|
+
chain: foundry,
|
|
87
|
+
publicClient,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
premintClient.apiClient.getSignature = vi
|
|
91
|
+
.fn<any, ReturnType<typeof premintClient.apiClient.getSignature>>()
|
|
92
|
+
.mockResolvedValue({
|
|
93
|
+
collection: {
|
|
94
|
+
contractAdmin: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
95
|
+
contractName: "Testing Contract",
|
|
96
|
+
contractURI:
|
|
97
|
+
"ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
|
|
98
|
+
},
|
|
99
|
+
premintConfig: {
|
|
100
|
+
deleted: false,
|
|
101
|
+
tokenConfig: {
|
|
102
|
+
fixedPriceMinter: getDefaultFixedPriceMinterAddress(chain.id),
|
|
103
|
+
maxSupply: 18446744073709551615n,
|
|
104
|
+
maxTokensPerAddress: 0n,
|
|
105
|
+
mintDuration: 604800n,
|
|
106
|
+
mintStart: 0n,
|
|
107
|
+
pricePerToken: 0n,
|
|
108
|
+
royaltyBPS: 1000,
|
|
109
|
+
royaltyMintSchedule: 0,
|
|
110
|
+
royaltyRecipient: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
111
|
+
tokenURI:
|
|
112
|
+
"ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
|
|
113
|
+
},
|
|
114
|
+
uid: 3,
|
|
115
|
+
version: 0,
|
|
116
|
+
},
|
|
117
|
+
premintConfigVersion: PremintConfigVersion.V1,
|
|
118
|
+
signature:
|
|
119
|
+
"0x70fc1d6e862c42f2b0e4a062f4eb973cc8692df58a24b71b4fe91ae7baa5a26d2c99b1b8ab61f64ff431bf30b0897877b11b7405542c90b89b041808f1561a6c1c",
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
premintClient.apiClient.postSignature = vi.fn();
|
|
123
|
+
|
|
124
|
+
const simulateContractParameters = await premintClient.makeMintParameters(
|
|
125
|
+
{
|
|
126
|
+
minterAccount: deployerAccount!,
|
|
127
|
+
tokenContract: "0xf8dA7f53c283d898818af7FB9d98103F559bDac2",
|
|
128
|
+
uid: 3,
|
|
129
|
+
mintArguments: {
|
|
130
|
+
quantityToMint: 1,
|
|
131
|
+
mintComment: "",
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
);
|
|
135
|
+
const { request: simulateRequest } = await publicClient.simulateContract(
|
|
136
|
+
simulateContractParameters,
|
|
137
|
+
);
|
|
138
|
+
const hash = await walletClient.writeContract(simulateRequest);
|
|
139
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
140
|
+
const { premintedLog, urls } =
|
|
141
|
+
premintClient.getDataFromPremintReceipt(receipt);
|
|
142
|
+
|
|
143
|
+
expect(urls).toEqual({
|
|
144
|
+
explorer:
|
|
145
|
+
"https://undefined/token/0xf8dA7f53c283d898818af7FB9d98103F559bDac2/instance/1",
|
|
146
|
+
zoraCollect:
|
|
147
|
+
"https://testnet.zora.co/collect/zgor:0xf8dA7f53c283d898818af7FB9d98103F559bDac2/1",
|
|
148
|
+
zoraManage:
|
|
149
|
+
"https://testnet.zora.co/collect/zgor:0xf8dA7f53c283d898818af7FB9d98103F559bDac2/1",
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
expect(premintedLog).toEqual({
|
|
153
|
+
contractAddress: "0xf8dA7f53c283d898818af7FB9d98103F559bDac2",
|
|
154
|
+
createdNewContract: expect.any(Boolean),
|
|
155
|
+
minter: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
156
|
+
quantityMinted: 1n,
|
|
157
|
+
tokenId: 1n,
|
|
158
|
+
uid: 3,
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
20 * 1000,
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe("ZoraCreator1155Premint - v2 signatures", () => {
|
|
166
|
+
anvilTest(
|
|
167
|
+
"can sign on the forked premint contract",
|
|
168
|
+
async ({ viemClients: { walletClient, publicClient, chain } }) => {
|
|
169
|
+
const [creatorAccount, createReferralAccount] =
|
|
170
|
+
await walletClient.getAddresses();
|
|
171
|
+
const premintClient = createPremintClient({
|
|
172
|
+
chain,
|
|
173
|
+
publicClient,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
premintClient.apiClient.getNextUID = vi
|
|
177
|
+
.fn<any, ReturnType<typeof premintClient.apiClient.getNextUID>>()
|
|
178
|
+
.mockResolvedValue(3);
|
|
179
|
+
premintClient.apiClient.postSignature = vi
|
|
180
|
+
.fn<Parameters<typeof premintClient.apiClient.postSignature>>()
|
|
181
|
+
.mockResolvedValue({ ok: true });
|
|
182
|
+
|
|
183
|
+
await premintClient.createPremint({
|
|
184
|
+
walletClient,
|
|
185
|
+
creatorAccount: creatorAccount!,
|
|
186
|
+
checkSignature: true,
|
|
187
|
+
collection: {
|
|
188
|
+
contractAdmin: creatorAccount!,
|
|
189
|
+
contractName: "Testing Contract Premint V2",
|
|
190
|
+
contractURI:
|
|
191
|
+
"ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
|
|
192
|
+
},
|
|
193
|
+
premintConfigVersion: PremintConfigVersion.V2,
|
|
194
|
+
tokenCreationConfig: {
|
|
195
|
+
tokenURI:
|
|
196
|
+
"ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
|
|
197
|
+
createReferral: createReferralAccount,
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const expectedPostSignatureArgs: Parameters<
|
|
202
|
+
typeof premintClient.apiClient.postSignature
|
|
203
|
+
>[0] = {
|
|
204
|
+
collection: {
|
|
205
|
+
contractAdmin: creatorAccount!,
|
|
206
|
+
contractName: "Testing Contract Premint V2",
|
|
207
|
+
contractURI:
|
|
208
|
+
"ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
|
|
209
|
+
},
|
|
210
|
+
premintConfig: {
|
|
211
|
+
deleted: false,
|
|
212
|
+
tokenConfig: {
|
|
213
|
+
fixedPriceMinter: "0x04E2516A2c207E84a1839755675dfd8eF6302F0a",
|
|
214
|
+
maxSupply: 18446744073709551615n,
|
|
215
|
+
maxTokensPerAddress: 0n,
|
|
216
|
+
mintDuration: 604800n,
|
|
217
|
+
mintStart: 0n,
|
|
218
|
+
pricePerToken: 0n,
|
|
219
|
+
royaltyBPS: 1000,
|
|
220
|
+
payoutRecipient: creatorAccount!,
|
|
221
|
+
createReferral: createReferralAccount!,
|
|
222
|
+
tokenURI:
|
|
223
|
+
"ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
|
|
224
|
+
},
|
|
225
|
+
uid: 3,
|
|
226
|
+
version: 0,
|
|
227
|
+
},
|
|
228
|
+
premintConfigVersion: PremintConfigVersion.V2,
|
|
229
|
+
signature:
|
|
230
|
+
"0x8be7932b0b31bdb7fc9269b756e0d0c9514519f083d86576e23b73c033d8ed8440ea363bc8bba0ec5c30eb6bbdf796163a324201bc7520965037102518fb5e991c",
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
expect(premintClient.apiClient.postSignature).toHaveBeenCalledWith(
|
|
234
|
+
expectedPostSignatureArgs,
|
|
235
|
+
);
|
|
236
|
+
},
|
|
237
|
+
20 * 1000,
|
|
238
|
+
);
|
|
239
|
+
});
|
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
import { Address, zeroAddress } from "viem";
|
|
2
|
+
import { foundry } from "viem/chains";
|
|
3
|
+
import { describe, expect } from "vitest";
|
|
4
|
+
import { parseEther } from "viem";
|
|
5
|
+
import {
|
|
6
|
+
zoraCreator1155PremintExecutorImplABI as preminterAbi,
|
|
7
|
+
zoraCreator1155ImplABI,
|
|
8
|
+
zoraCreator1155FactoryImplAddress,
|
|
9
|
+
zoraCreator1155FactoryImplConfig,
|
|
10
|
+
} from "@zoralabs/protocol-deployments";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
premintTypedDataDefinition,
|
|
14
|
+
isValidSignature,
|
|
15
|
+
recoverCreatorFromCreatorAttribution,
|
|
16
|
+
getPremintExecutorAddress,
|
|
17
|
+
getPremintMintCosts,
|
|
18
|
+
} from "./preminter";
|
|
19
|
+
import {
|
|
20
|
+
ContractCreationConfig,
|
|
21
|
+
PremintConfigV1,
|
|
22
|
+
TokenCreationConfigV1,
|
|
23
|
+
PremintConfigVersion,
|
|
24
|
+
TokenCreationConfigV2,
|
|
25
|
+
PremintConfigV2,
|
|
26
|
+
MintArguments,
|
|
27
|
+
} from "./contract-types";
|
|
28
|
+
import { AnvilViemClientsTest, forkUrls, makeAnvilTest } from "src/anvil";
|
|
29
|
+
|
|
30
|
+
// create token and contract creation config:
|
|
31
|
+
const defaultContractConfig = ({
|
|
32
|
+
contractAdmin,
|
|
33
|
+
}: {
|
|
34
|
+
contractAdmin: Address;
|
|
35
|
+
}): ContractCreationConfig => ({
|
|
36
|
+
contractAdmin,
|
|
37
|
+
contractURI: "ipfs://asdfasdfasdf",
|
|
38
|
+
contractName: "My fun NFT",
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const defaultTokenConfigV1 = (
|
|
42
|
+
fixedPriceMinterAddress: Address,
|
|
43
|
+
creatorAccount: Address,
|
|
44
|
+
): TokenCreationConfigV1 => ({
|
|
45
|
+
tokenURI: "ipfs://tokenIpfsId0",
|
|
46
|
+
maxSupply: 100n,
|
|
47
|
+
maxTokensPerAddress: 10n,
|
|
48
|
+
pricePerToken: 0n,
|
|
49
|
+
mintStart: 0n,
|
|
50
|
+
mintDuration: 100n,
|
|
51
|
+
royaltyMintSchedule: 30,
|
|
52
|
+
royaltyBPS: 200,
|
|
53
|
+
royaltyRecipient: creatorAccount,
|
|
54
|
+
fixedPriceMinter: fixedPriceMinterAddress,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const defaultTokenConfigV2 = (
|
|
58
|
+
fixedPriceMinterAddress: Address,
|
|
59
|
+
creatorAccount: Address,
|
|
60
|
+
createReferral: Address,
|
|
61
|
+
): TokenCreationConfigV2 => ({
|
|
62
|
+
tokenURI: "ipfs://tokenIpfsId0",
|
|
63
|
+
maxSupply: 100n,
|
|
64
|
+
maxTokensPerAddress: 10n,
|
|
65
|
+
pricePerToken: 0n,
|
|
66
|
+
mintStart: 0n,
|
|
67
|
+
mintDuration: 100n,
|
|
68
|
+
royaltyBPS: 200,
|
|
69
|
+
payoutRecipient: creatorAccount,
|
|
70
|
+
fixedPriceMinter: fixedPriceMinterAddress,
|
|
71
|
+
createReferral,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const defaultPremintConfigV1 = ({
|
|
75
|
+
fixedPriceMinter,
|
|
76
|
+
creatorAccount,
|
|
77
|
+
}: {
|
|
78
|
+
fixedPriceMinter: Address;
|
|
79
|
+
creatorAccount: Address;
|
|
80
|
+
}): PremintConfigV1 => ({
|
|
81
|
+
tokenConfig: defaultTokenConfigV1(fixedPriceMinter, creatorAccount),
|
|
82
|
+
deleted: false,
|
|
83
|
+
uid: 105,
|
|
84
|
+
version: 0,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const defaultPremintConfigV2 = ({
|
|
88
|
+
fixedPriceMinter,
|
|
89
|
+
creatorAccount,
|
|
90
|
+
createReferral = zeroAddress,
|
|
91
|
+
}: {
|
|
92
|
+
fixedPriceMinter: Address;
|
|
93
|
+
creatorAccount: Address;
|
|
94
|
+
createReferral?: Address;
|
|
95
|
+
}): PremintConfigV2 => ({
|
|
96
|
+
tokenConfig: defaultTokenConfigV2(
|
|
97
|
+
fixedPriceMinter,
|
|
98
|
+
creatorAccount,
|
|
99
|
+
createReferral,
|
|
100
|
+
),
|
|
101
|
+
deleted: false,
|
|
102
|
+
uid: 106,
|
|
103
|
+
version: 0,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const PREMINTER_ADDRESS = getPremintExecutorAddress();
|
|
107
|
+
|
|
108
|
+
const anvilTest = makeAnvilTest({
|
|
109
|
+
forkUrl: forkUrls.zoraSepolia,
|
|
110
|
+
forkBlockNumber: 1265490,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
async function setupContracts({
|
|
114
|
+
viemClients: { walletClient, testClient, publicClient },
|
|
115
|
+
}: AnvilViemClientsTest) {
|
|
116
|
+
// JSON-RPC Account
|
|
117
|
+
const [deployerAccount, creatorAccount, collectorAccount] =
|
|
118
|
+
(await walletClient.getAddresses()) as [Address, Address, Address, Address];
|
|
119
|
+
|
|
120
|
+
// deploy signature minter contract
|
|
121
|
+
await testClient.setBalance({
|
|
122
|
+
address: deployerAccount,
|
|
123
|
+
value: parseEther("10"),
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const fixedPriceMinterAddress = await publicClient.readContract({
|
|
127
|
+
abi: zoraCreator1155FactoryImplConfig.abi,
|
|
128
|
+
address: zoraCreator1155FactoryImplAddress[999],
|
|
129
|
+
functionName: "fixedPriceMinter",
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
accounts: {
|
|
134
|
+
deployerAccount,
|
|
135
|
+
creatorAccount,
|
|
136
|
+
collectorAccount,
|
|
137
|
+
},
|
|
138
|
+
fixedPriceMinterAddress,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const zoraSepoliaAnvilTest = makeAnvilTest({
|
|
143
|
+
forkUrl: forkUrls.zoraSepolia,
|
|
144
|
+
forkBlockNumber: 3118200,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe("ZoraCreator1155Preminter", () => {
|
|
148
|
+
// skip for now - we need to make this work on zora testnet chain too
|
|
149
|
+
anvilTest(
|
|
150
|
+
"can sign on the forked premint contract",
|
|
151
|
+
async ({ viemClients }) => {
|
|
152
|
+
const {
|
|
153
|
+
fixedPriceMinterAddress,
|
|
154
|
+
accounts: { creatorAccount },
|
|
155
|
+
} = await setupContracts({ viemClients });
|
|
156
|
+
const premintConfig = defaultPremintConfigV1({
|
|
157
|
+
fixedPriceMinter: fixedPriceMinterAddress,
|
|
158
|
+
creatorAccount,
|
|
159
|
+
});
|
|
160
|
+
const contractConfig = defaultContractConfig({
|
|
161
|
+
contractAdmin: creatorAccount,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const preminterAddress = getPremintExecutorAddress();
|
|
165
|
+
|
|
166
|
+
const contractAddress = await viemClients.publicClient.readContract({
|
|
167
|
+
abi: preminterAbi,
|
|
168
|
+
address: preminterAddress,
|
|
169
|
+
functionName: "getContractAddress",
|
|
170
|
+
args: [contractConfig],
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const signedMessage = await viemClients.walletClient.signTypedData({
|
|
174
|
+
...premintTypedDataDefinition({
|
|
175
|
+
verifyingContract: contractAddress,
|
|
176
|
+
chainId: 999,
|
|
177
|
+
premintConfig,
|
|
178
|
+
premintConfigVersion: PremintConfigVersion.V1,
|
|
179
|
+
}),
|
|
180
|
+
account: creatorAccount,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
console.log({
|
|
184
|
+
creatorAccount,
|
|
185
|
+
signedMessage,
|
|
186
|
+
contractConfig,
|
|
187
|
+
premintConfig,
|
|
188
|
+
contractAddress,
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
20 * 1000,
|
|
192
|
+
);
|
|
193
|
+
zoraSepoliaAnvilTest(
|
|
194
|
+
"can sign and recover a v1 premint config signature",
|
|
195
|
+
async ({ viemClients }) => {
|
|
196
|
+
const {
|
|
197
|
+
fixedPriceMinterAddress,
|
|
198
|
+
accounts: { creatorAccount },
|
|
199
|
+
} = await setupContracts({ viemClients });
|
|
200
|
+
|
|
201
|
+
const premintConfig = defaultPremintConfigV1({
|
|
202
|
+
fixedPriceMinter: fixedPriceMinterAddress,
|
|
203
|
+
creatorAccount,
|
|
204
|
+
});
|
|
205
|
+
const contractConfig = defaultContractConfig({
|
|
206
|
+
contractAdmin: creatorAccount,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const tokenContract = await viemClients.publicClient.readContract({
|
|
210
|
+
abi: preminterAbi,
|
|
211
|
+
address: PREMINTER_ADDRESS,
|
|
212
|
+
functionName: "getContractAddress",
|
|
213
|
+
args: [contractConfig],
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// sign message containing contract and token creation config and uid
|
|
217
|
+
const signedMessage = await viemClients.walletClient.signTypedData({
|
|
218
|
+
...premintTypedDataDefinition({
|
|
219
|
+
verifyingContract: tokenContract,
|
|
220
|
+
// we need to sign here for the anvil chain, cause thats where it is run on
|
|
221
|
+
chainId: foundry.id,
|
|
222
|
+
premintConfig,
|
|
223
|
+
premintConfigVersion: PremintConfigVersion.V1,
|
|
224
|
+
}),
|
|
225
|
+
account: creatorAccount,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// recover and verify address is correct
|
|
229
|
+
const { recoveredAddress, isAuthorized } = await isValidSignature({
|
|
230
|
+
collection: contractConfig,
|
|
231
|
+
chainId: viemClients.publicClient.chain!.id,
|
|
232
|
+
premintConfig,
|
|
233
|
+
premintConfigVersion: PremintConfigVersion.V1,
|
|
234
|
+
publicClient: viemClients.publicClient,
|
|
235
|
+
signature: signedMessage,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
expect(recoveredAddress).to.equal(creatorAccount);
|
|
239
|
+
expect(isAuthorized).toBe(true);
|
|
240
|
+
|
|
241
|
+
expect(recoveredAddress).to.equal(creatorAccount);
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
20 * 1000,
|
|
245
|
+
);
|
|
246
|
+
zoraSepoliaAnvilTest(
|
|
247
|
+
"can sign and recover a v2 premint config signature",
|
|
248
|
+
async ({ viemClients }) => {
|
|
249
|
+
const {
|
|
250
|
+
fixedPriceMinterAddress,
|
|
251
|
+
accounts: { creatorAccount },
|
|
252
|
+
} = await setupContracts({ viemClients });
|
|
253
|
+
|
|
254
|
+
const premintConfig = defaultPremintConfigV2({
|
|
255
|
+
creatorAccount,
|
|
256
|
+
fixedPriceMinter: fixedPriceMinterAddress,
|
|
257
|
+
createReferral: creatorAccount,
|
|
258
|
+
});
|
|
259
|
+
const contractConfig = defaultContractConfig({
|
|
260
|
+
contractAdmin: creatorAccount,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const tokenContract = await viemClients.publicClient.readContract({
|
|
264
|
+
abi: preminterAbi,
|
|
265
|
+
address: PREMINTER_ADDRESS,
|
|
266
|
+
functionName: "getContractAddress",
|
|
267
|
+
args: [contractConfig],
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// sign message containing contract and token creation config and uid
|
|
271
|
+
const signedMessage = await viemClients.walletClient.signTypedData({
|
|
272
|
+
...premintTypedDataDefinition({
|
|
273
|
+
verifyingContract: tokenContract,
|
|
274
|
+
// we need to sign here for the anvil chain, cause thats where it is run on
|
|
275
|
+
chainId: foundry.id,
|
|
276
|
+
premintConfig,
|
|
277
|
+
premintConfigVersion: PremintConfigVersion.V2,
|
|
278
|
+
}),
|
|
279
|
+
account: creatorAccount,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// recover and verify address is correct
|
|
283
|
+
const { recoveredAddress, isAuthorized } = await isValidSignature({
|
|
284
|
+
collection: contractConfig,
|
|
285
|
+
chainId: viemClients.publicClient.chain!.id,
|
|
286
|
+
premintConfig,
|
|
287
|
+
premintConfigVersion: PremintConfigVersion.V2,
|
|
288
|
+
publicClient: viemClients.publicClient,
|
|
289
|
+
signature: signedMessage,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
expect(recoveredAddress).to.equal(creatorAccount);
|
|
293
|
+
expect(isAuthorized).toBe(true);
|
|
294
|
+
|
|
295
|
+
expect(recoveredAddress).to.equal(creatorAccount);
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
20 * 1000,
|
|
299
|
+
);
|
|
300
|
+
zoraSepoliaAnvilTest(
|
|
301
|
+
"can sign and mint multiple tokens",
|
|
302
|
+
async ({ viemClients }) => {
|
|
303
|
+
const {
|
|
304
|
+
fixedPriceMinterAddress,
|
|
305
|
+
accounts: { creatorAccount, collectorAccount },
|
|
306
|
+
} = await setupContracts({ viemClients });
|
|
307
|
+
// setup contract and token creation parameters
|
|
308
|
+
const premintConfig1 = defaultPremintConfigV1({
|
|
309
|
+
fixedPriceMinter: fixedPriceMinterAddress,
|
|
310
|
+
creatorAccount,
|
|
311
|
+
});
|
|
312
|
+
const contractConfig = defaultContractConfig({
|
|
313
|
+
contractAdmin: creatorAccount,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// lets make it a random number to not break the existing tests that expect fresh data
|
|
317
|
+
premintConfig1.uid = Math.round(Math.random() * 1000000);
|
|
318
|
+
|
|
319
|
+
let contractAddress = await viemClients.publicClient.readContract({
|
|
320
|
+
abi: preminterAbi,
|
|
321
|
+
address: PREMINTER_ADDRESS,
|
|
322
|
+
functionName: "getContractAddress",
|
|
323
|
+
args: [contractConfig],
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// have creator sign the message to create the contract
|
|
327
|
+
// and the token
|
|
328
|
+
const signedMessage = await viemClients.walletClient.signTypedData({
|
|
329
|
+
...premintTypedDataDefinition({
|
|
330
|
+
verifyingContract: contractAddress,
|
|
331
|
+
// we need to sign here for the anvil chain, cause thats where it is run on
|
|
332
|
+
chainId: foundry.id,
|
|
333
|
+
premintConfig: premintConfig1,
|
|
334
|
+
premintConfigVersion: PremintConfigVersion.V1,
|
|
335
|
+
}),
|
|
336
|
+
account: creatorAccount,
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
const quantityToMint = 2n;
|
|
340
|
+
|
|
341
|
+
const valueToSend = (
|
|
342
|
+
await getPremintMintCosts({
|
|
343
|
+
publicClient: viemClients.publicClient,
|
|
344
|
+
quantityToMint,
|
|
345
|
+
tokenContract: contractAddress,
|
|
346
|
+
tokenPrice: premintConfig1.tokenConfig.pricePerToken,
|
|
347
|
+
})
|
|
348
|
+
).totalCost;
|
|
349
|
+
|
|
350
|
+
await viemClients.testClient.setBalance({
|
|
351
|
+
address: collectorAccount,
|
|
352
|
+
value: parseEther("10"),
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// get the premint status - it should not be minted
|
|
356
|
+
let [contractCreated, tokenId] =
|
|
357
|
+
await viemClients.publicClient.readContract({
|
|
358
|
+
abi: preminterAbi,
|
|
359
|
+
address: PREMINTER_ADDRESS,
|
|
360
|
+
functionName: "premintStatus",
|
|
361
|
+
args: [contractAddress, premintConfig1.uid],
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
expect(contractCreated).toBe(false);
|
|
365
|
+
expect(tokenId).toBe(0n);
|
|
366
|
+
|
|
367
|
+
const mintArguments: MintArguments = {
|
|
368
|
+
mintComment: "",
|
|
369
|
+
mintRecipient: collectorAccount,
|
|
370
|
+
mintRewardsRecipients: [],
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
// now have the collector execute the first signed message;
|
|
374
|
+
// it should create the contract, the token,
|
|
375
|
+
// and min the quantity to mint tokens to the collector
|
|
376
|
+
// the signature along with contract + token creation
|
|
377
|
+
// parameters are required to call this function
|
|
378
|
+
const mintHash = await viemClients.walletClient.writeContract({
|
|
379
|
+
abi: preminterAbi,
|
|
380
|
+
functionName: "premintV1",
|
|
381
|
+
account: collectorAccount,
|
|
382
|
+
chain: foundry,
|
|
383
|
+
address: PREMINTER_ADDRESS,
|
|
384
|
+
args: [
|
|
385
|
+
contractConfig,
|
|
386
|
+
premintConfig1,
|
|
387
|
+
signedMessage,
|
|
388
|
+
quantityToMint,
|
|
389
|
+
mintArguments,
|
|
390
|
+
],
|
|
391
|
+
value: valueToSend,
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
// ensure it succeeded
|
|
395
|
+
const receipt = await viemClients.publicClient.waitForTransactionReceipt({
|
|
396
|
+
hash: mintHash,
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
expect(receipt.status).toBe("success");
|
|
400
|
+
|
|
401
|
+
// fetch the premint token id
|
|
402
|
+
[contractCreated, tokenId] = await viemClients.publicClient.readContract({
|
|
403
|
+
abi: preminterAbi,
|
|
404
|
+
address: PREMINTER_ADDRESS,
|
|
405
|
+
functionName: "premintStatus",
|
|
406
|
+
args: [contractAddress, premintConfig1.uid],
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
expect(contractCreated).toBe(true);
|
|
410
|
+
expect(tokenId).not.toBe(0n);
|
|
411
|
+
|
|
412
|
+
// now use what was created, to get the balance from the created contract
|
|
413
|
+
const tokenBalance = await viemClients.publicClient.readContract({
|
|
414
|
+
abi: zoraCreator1155ImplABI,
|
|
415
|
+
address: contractAddress,
|
|
416
|
+
functionName: "balanceOf",
|
|
417
|
+
args: [collectorAccount, tokenId],
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// get token balance - should be amount that was created
|
|
421
|
+
expect(tokenBalance).toBe(quantityToMint);
|
|
422
|
+
|
|
423
|
+
const premintConfig2 = defaultPremintConfigV2({
|
|
424
|
+
creatorAccount,
|
|
425
|
+
fixedPriceMinter: fixedPriceMinterAddress,
|
|
426
|
+
createReferral: creatorAccount,
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// sign the message to create the second token
|
|
430
|
+
const signedMessage2 = await viemClients.walletClient.signTypedData({
|
|
431
|
+
...premintTypedDataDefinition({
|
|
432
|
+
verifyingContract: contractAddress,
|
|
433
|
+
chainId: foundry.id,
|
|
434
|
+
premintConfig: premintConfig2,
|
|
435
|
+
premintConfigVersion: PremintConfigVersion.V2,
|
|
436
|
+
}),
|
|
437
|
+
account: creatorAccount,
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
const quantityToMint2 = 4n;
|
|
441
|
+
|
|
442
|
+
const valueToSend2 = (
|
|
443
|
+
await getPremintMintCosts({
|
|
444
|
+
publicClient: viemClients.publicClient,
|
|
445
|
+
quantityToMint: quantityToMint2,
|
|
446
|
+
tokenContract: contractAddress,
|
|
447
|
+
tokenPrice: premintConfig2.tokenConfig.pricePerToken,
|
|
448
|
+
})
|
|
449
|
+
).totalCost;
|
|
450
|
+
|
|
451
|
+
const simulationResult = await viemClients.publicClient.simulateContract({
|
|
452
|
+
abi: preminterAbi,
|
|
453
|
+
functionName: "premintV2",
|
|
454
|
+
account: collectorAccount,
|
|
455
|
+
chain: foundry,
|
|
456
|
+
address: PREMINTER_ADDRESS,
|
|
457
|
+
args: [
|
|
458
|
+
contractConfig,
|
|
459
|
+
premintConfig2,
|
|
460
|
+
signedMessage2,
|
|
461
|
+
quantityToMint2,
|
|
462
|
+
mintArguments,
|
|
463
|
+
],
|
|
464
|
+
value: valueToSend2,
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
// now have the collector execute the second signed message.
|
|
468
|
+
// it should create a new token against the existing contract
|
|
469
|
+
const mintHash2 = await viemClients.walletClient.writeContract(
|
|
470
|
+
simulationResult.request,
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
const premintV2Receipt =
|
|
474
|
+
await viemClients.publicClient.waitForTransactionReceipt({
|
|
475
|
+
hash: mintHash2,
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
expect(premintV2Receipt.status).toBe("success");
|
|
479
|
+
|
|
480
|
+
// now premint status for the second mint, it should be minted
|
|
481
|
+
[, tokenId] = await viemClients.publicClient.readContract({
|
|
482
|
+
abi: preminterAbi,
|
|
483
|
+
address: PREMINTER_ADDRESS,
|
|
484
|
+
functionName: "premintStatus",
|
|
485
|
+
args: [contractAddress, premintConfig2.uid],
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
expect(tokenId).not.toBe(0n);
|
|
489
|
+
|
|
490
|
+
// get balance of second token
|
|
491
|
+
const tokenBalance2 = await viemClients.publicClient.readContract({
|
|
492
|
+
abi: zoraCreator1155ImplABI,
|
|
493
|
+
address: contractAddress,
|
|
494
|
+
functionName: "balanceOf",
|
|
495
|
+
args: [collectorAccount, tokenId],
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
expect(tokenBalance2).toBe(quantityToMint2);
|
|
499
|
+
},
|
|
500
|
+
// 10 second timeout
|
|
501
|
+
40 * 1000,
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
zoraSepoliaAnvilTest(
|
|
505
|
+
"can decode the CreatorAttribution event",
|
|
506
|
+
async ({ viemClients }) => {
|
|
507
|
+
const {
|
|
508
|
+
fixedPriceMinterAddress,
|
|
509
|
+
accounts: { creatorAccount, collectorAccount },
|
|
510
|
+
} = await setupContracts({ viemClients });
|
|
511
|
+
const premintConfig = defaultPremintConfigV2({
|
|
512
|
+
fixedPriceMinter: fixedPriceMinterAddress,
|
|
513
|
+
creatorAccount,
|
|
514
|
+
});
|
|
515
|
+
const contractConfig = defaultContractConfig({
|
|
516
|
+
contractAdmin: creatorAccount,
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
// lets make it a random number to not break the existing tests that expect fresh data
|
|
520
|
+
premintConfig.uid = Math.round(Math.random() * 1000000);
|
|
521
|
+
|
|
522
|
+
let contractAddress = await viemClients.publicClient.readContract({
|
|
523
|
+
abi: preminterAbi,
|
|
524
|
+
address: PREMINTER_ADDRESS,
|
|
525
|
+
functionName: "getContractAddress",
|
|
526
|
+
args: [contractConfig],
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
const signingChainId = foundry.id;
|
|
530
|
+
|
|
531
|
+
// have creator sign the message to create the contract
|
|
532
|
+
// and the token
|
|
533
|
+
const signedMessage = await viemClients.walletClient.signTypedData({
|
|
534
|
+
...premintTypedDataDefinition({
|
|
535
|
+
verifyingContract: contractAddress,
|
|
536
|
+
// we need to sign here for the anvil chain, cause thats where it is run on
|
|
537
|
+
chainId: signingChainId,
|
|
538
|
+
premintConfig,
|
|
539
|
+
premintConfigVersion: PremintConfigVersion.V2,
|
|
540
|
+
}),
|
|
541
|
+
account: creatorAccount,
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
const quantityToMint = 2n;
|
|
545
|
+
|
|
546
|
+
const valueToSend = (
|
|
547
|
+
await getPremintMintCosts({
|
|
548
|
+
publicClient: viemClients.publicClient,
|
|
549
|
+
quantityToMint,
|
|
550
|
+
tokenContract: contractAddress,
|
|
551
|
+
tokenPrice: premintConfig.tokenConfig.pricePerToken,
|
|
552
|
+
})
|
|
553
|
+
).totalCost;
|
|
554
|
+
|
|
555
|
+
await viemClients.testClient.setBalance({
|
|
556
|
+
address: collectorAccount,
|
|
557
|
+
value: parseEther("10"),
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
// now have the collector execute the first signed message;
|
|
561
|
+
// it should create the contract, the token,
|
|
562
|
+
// and min the quantity to mint tokens to the collector
|
|
563
|
+
// the signature along with contract + token creation
|
|
564
|
+
// parameters are required to call this function
|
|
565
|
+
const mintHash = await viemClients.walletClient.writeContract({
|
|
566
|
+
abi: preminterAbi,
|
|
567
|
+
functionName: "premintV2",
|
|
568
|
+
account: collectorAccount,
|
|
569
|
+
chain: foundry,
|
|
570
|
+
address: PREMINTER_ADDRESS,
|
|
571
|
+
args: [
|
|
572
|
+
contractConfig,
|
|
573
|
+
premintConfig,
|
|
574
|
+
signedMessage,
|
|
575
|
+
quantityToMint,
|
|
576
|
+
{
|
|
577
|
+
mintComment: "",
|
|
578
|
+
mintRecipient: collectorAccount,
|
|
579
|
+
mintRewardsRecipients: [],
|
|
580
|
+
},
|
|
581
|
+
],
|
|
582
|
+
value: valueToSend,
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
// ensure it succeeded
|
|
586
|
+
const receipt = await viemClients.publicClient.waitForTransactionReceipt({
|
|
587
|
+
hash: mintHash,
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
expect(receipt.status).toBe("success");
|
|
591
|
+
|
|
592
|
+
// get the CreatorAttribution event from the erc1155 contract:
|
|
593
|
+
const topics = await viemClients.publicClient.getContractEvents({
|
|
594
|
+
abi: zoraCreator1155ImplABI,
|
|
595
|
+
address: contractAddress,
|
|
596
|
+
eventName: "CreatorAttribution",
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
expect(topics.length).toBe(1);
|
|
600
|
+
|
|
601
|
+
const creatorAttributionEvent = topics[0]!;
|
|
602
|
+
|
|
603
|
+
const { creator: creatorFromEvent } = creatorAttributionEvent.args;
|
|
604
|
+
|
|
605
|
+
const recoveredSigner = await recoverCreatorFromCreatorAttribution({
|
|
606
|
+
creatorAttribution: creatorAttributionEvent.args,
|
|
607
|
+
chainId: signingChainId,
|
|
608
|
+
tokenContract: contractAddress,
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
expect(creatorFromEvent).toBe(creatorAccount);
|
|
612
|
+
expect(recoveredSigner).toBe(creatorFromEvent);
|
|
613
|
+
},
|
|
614
|
+
);
|
|
615
|
+
});
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { zoraSepolia, zoraTestnet } from "viem/chains";
|
|
2
|
+
import { describe } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { createPremintClient } from "src/premint/premint-client";
|
|
5
|
+
import { forkUrls, makeAnvilTest } from "src/anvil";
|
|
6
|
+
import { PremintConfigVersion } from "src/premint/contract-types";
|
|
7
|
+
|
|
8
|
+
const zoraGoerliTest = makeAnvilTest({
|
|
9
|
+
forkBlockNumber: 2107926,
|
|
10
|
+
forkUrl: forkUrls.zoraGoerli,
|
|
11
|
+
anvilChainId: zoraTestnet.id,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const zoraSepoliaTest = makeAnvilTest({
|
|
15
|
+
forkBlockNumber: 3118200,
|
|
16
|
+
forkUrl: forkUrls.zoraSepolia,
|
|
17
|
+
anvilChainId: zoraSepolia.id,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const tests = [
|
|
21
|
+
{
|
|
22
|
+
anvilTest: zoraGoerliTest,
|
|
23
|
+
chain: zoraTestnet,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
anvilTest: zoraSepoliaTest,
|
|
27
|
+
chain: zoraSepolia,
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
tests.forEach(({ anvilTest, chain }) => {
|
|
32
|
+
describe(chain.name, () => {
|
|
33
|
+
describe("ZoraCreator1155Premint", () => {
|
|
34
|
+
describe("v2 signatures", () => {
|
|
35
|
+
anvilTest(
|
|
36
|
+
"can sign and execute on the forked premint contract",
|
|
37
|
+
async ({
|
|
38
|
+
viemClients: { walletClient, publicClient, testClient },
|
|
39
|
+
}) => {
|
|
40
|
+
const [creatorAccount, createReferralAccount, minterAccount] =
|
|
41
|
+
await walletClient.getAddresses();
|
|
42
|
+
const premintClient = createPremintClient({
|
|
43
|
+
chain,
|
|
44
|
+
publicClient,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const { uid, verifyingContract } =
|
|
48
|
+
await premintClient.createPremint({
|
|
49
|
+
walletClient,
|
|
50
|
+
creatorAccount: creatorAccount!,
|
|
51
|
+
checkSignature: true,
|
|
52
|
+
collection: {
|
|
53
|
+
contractAdmin: creatorAccount!,
|
|
54
|
+
contractName: "Testing Contract Premint V2",
|
|
55
|
+
contractURI:
|
|
56
|
+
"ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3f",
|
|
57
|
+
},
|
|
58
|
+
premintConfigVersion: PremintConfigVersion.V2,
|
|
59
|
+
tokenCreationConfig: {
|
|
60
|
+
tokenURI:
|
|
61
|
+
"ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2f",
|
|
62
|
+
createReferral: createReferralAccount!,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const mintParameters = await premintClient.makeMintParameters({
|
|
67
|
+
minterAccount: minterAccount!,
|
|
68
|
+
tokenContract: verifyingContract,
|
|
69
|
+
uid,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const mintCosts = await premintClient.getMintCosts({
|
|
73
|
+
tokenContract: verifyingContract,
|
|
74
|
+
quantityToMint: 1n,
|
|
75
|
+
pricePerToken: 0n,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
await testClient.setBalance({
|
|
79
|
+
address: minterAccount!,
|
|
80
|
+
value: mintCosts.totalCost,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// if simulation succeeds, mint will succeed
|
|
84
|
+
await publicClient.simulateContract(mintParameters);
|
|
85
|
+
},
|
|
86
|
+
20 * 1000,
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("v1 signatures", () => {
|
|
91
|
+
anvilTest(
|
|
92
|
+
"can sign and execute on the forked premint contract",
|
|
93
|
+
async ({
|
|
94
|
+
viemClients: { walletClient, publicClient, testClient },
|
|
95
|
+
}) => {
|
|
96
|
+
const [creatorAccount, minterAccount] =
|
|
97
|
+
await walletClient.getAddresses();
|
|
98
|
+
const premintClient = createPremintClient({
|
|
99
|
+
chain,
|
|
100
|
+
publicClient,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const { uid, verifyingContract } =
|
|
104
|
+
await premintClient.createPremint({
|
|
105
|
+
walletClient,
|
|
106
|
+
creatorAccount: creatorAccount!,
|
|
107
|
+
checkSignature: true,
|
|
108
|
+
collection: {
|
|
109
|
+
contractAdmin: creatorAccount!,
|
|
110
|
+
contractName: `Testing Contract Premint V1 ${publicClient.chain?.name}`,
|
|
111
|
+
contractURI:
|
|
112
|
+
"ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3fg",
|
|
113
|
+
},
|
|
114
|
+
premintConfigVersion: PremintConfigVersion.V1,
|
|
115
|
+
tokenCreationConfig: {
|
|
116
|
+
tokenURI:
|
|
117
|
+
"ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const mintParameters = await premintClient.makeMintParameters({
|
|
122
|
+
minterAccount: minterAccount!,
|
|
123
|
+
tokenContract: verifyingContract,
|
|
124
|
+
uid,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const mintCosts = await premintClient.getMintCosts({
|
|
128
|
+
tokenContract: verifyingContract,
|
|
129
|
+
quantityToMint: 1n,
|
|
130
|
+
pricePerToken: 0n,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
await testClient.setBalance({
|
|
134
|
+
address: minterAccount!,
|
|
135
|
+
value: mintCosts.totalCost,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// if simulation succeeds, mint will succeed
|
|
139
|
+
await publicClient.simulateContract(mintParameters);
|
|
140
|
+
},
|
|
141
|
+
20 * 1000,
|
|
142
|
+
);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
});
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineConfig } from "tsup";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
entry: ["src/index.ts"],
|
|
5
|
+
sourcemap: true,
|
|
6
|
+
clean: true,
|
|
7
|
+
tsconfig: "tsconfig.build.json",
|
|
8
|
+
dts: false,
|
|
9
|
+
format: ["cjs", "esm"],
|
|
10
|
+
onSuccess:
|
|
11
|
+
"tsc --project tsconfig.build.json --emitDeclarationOnly --declaration --declarationMap",
|
|
12
|
+
});
|