@zoralabs/protocol-deployments 0.0.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.
- package/.env.anvil +2 -0
- package/.turbo/turbo-build.log +34 -0
- package/CHANGELOG.md +34 -0
- package/README.md +20 -0
- package/addresses/1.json +14 -0
- package/addresses/10.json +14 -0
- package/addresses/11155111.json +9 -0
- package/addresses/420.json +14 -0
- package/addresses/424.json +11 -0
- package/addresses/5.json +14 -0
- package/addresses/58008.json +11 -0
- package/addresses/7777777.json +14 -0
- package/addresses/8453.json +14 -0
- package/addresses/84531.json +14 -0
- package/addresses/999.json +14 -0
- package/addresses/999999999.json +13 -0
- package/chainConfigs/1.json +5 -0
- package/chainConfigs/10.json +5 -0
- package/chainConfigs/11155111.json +4 -0
- package/chainConfigs/420.json +5 -0
- package/chainConfigs/424.json +5 -0
- package/chainConfigs/5.json +5 -0
- package/chainConfigs/58008.json +4 -0
- package/chainConfigs/7777777.json +5 -0
- package/chainConfigs/8453.json +5 -0
- package/chainConfigs/84531.json +5 -0
- package/chainConfigs/999.json +5 -0
- package/chainConfigs/999999999.json +5 -0
- package/deterministicConfig/factoryProxy/params.json +10 -0
- package/deterministicConfig/factoryProxy/signatures.json +14 -0
- package/deterministicConfig/premintExecutorProxy/params.json +10 -0
- package/deterministicConfig/premintExecutorProxy/signatures.json +11 -0
- package/deterministicConfig/upgradeGate/params.json +7 -0
- package/deterministicConfig/upgradeGate/signatures.json +14 -0
- package/dist/index.cjs +3360 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +3314 -0
- package/dist/index.js.map +1 -0
- package/dist/package/batchPublish.test.d.ts +451 -0
- package/dist/package/batchPublish.test.d.ts.map +1 -0
- package/dist/package/chainConfigs.d.ts +61 -0
- package/dist/package/chainConfigs.d.ts.map +1 -0
- package/dist/package/deployment.d.ts +32 -0
- package/dist/package/deployment.d.ts.map +1 -0
- package/dist/package/index.d.ts +3 -0
- package/dist/package/index.d.ts.map +1 -0
- package/dist/package/wagmiGenerated.d.ts +6810 -0
- package/dist/package/wagmiGenerated.d.ts.map +1 -0
- package/dist/script/copy-deployed-contracts.d.ts +2 -0
- package/dist/script/copy-deployed-contracts.d.ts.map +1 -0
- package/dist/script/signDeploymentTransactions.d.ts +2 -0
- package/dist/script/signDeploymentTransactions.d.ts.map +1 -0
- package/foundry.toml +40 -0
- package/package/batchPublish.test.ts +326 -0
- package/package/chainConfigs.ts +60 -0
- package/package/deployment.ts +94 -0
- package/package/index.ts +5 -0
- package/package/wagmiGenerated.ts +3472 -0
- package/package.json +44 -0
- package/remappings.txt +9 -0
- package/script/CalculateDeterministicParams.s.sol +84 -0
- package/script/DeployMintersAndImplementations.s.sol +31 -0
- package/script/DeployNewImplementation.s.sol +26 -0
- package/script/DeployPreminterImpl.s.sol +23 -0
- package/script/DeployProxiesToNewChain.s.sol +42 -0
- package/script/DeployUpgradeGate.s.sol +27 -0
- package/script/Upgrade.s.sol +83 -0
- package/script/UpgradePreminter.s.sol +34 -0
- package/script/bundle-chainConfigs.mjs +36 -0
- package/script/copy-deployed-contracts.ts +66 -0
- package/script/signDeploymentTransactions.ts +277 -0
- package/test/NewFactoryProxyDeployer.t.sol +127 -0
- package/test/ZoraCreator1155Factory_Fork.t.sol +151 -0
- package/test/ZoraCreator1155PremintExecutorForkTest.t.sol +93 -0
- package/tsconfig.json +25 -0
- package/tsup.config.ts +10 -0
- package/wagmi.config.ts +113 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { createAccount } from "@turnkey/viem";
|
|
2
|
+
import { TurnkeyClient } from "@turnkey/http";
|
|
3
|
+
import { Address, encodeFunctionData, parseAbi, LocalAccount, Hex } from "viem";
|
|
4
|
+
import { ApiKeyStamper } from "@turnkey/api-key-stamper";
|
|
5
|
+
import { glob } from "glob";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
import * as dotenv from "dotenv";
|
|
8
|
+
import { writeFile, readFile } from "fs/promises";
|
|
9
|
+
import {
|
|
10
|
+
ConfiguredSalt,
|
|
11
|
+
DeterministicDeploymentConfig,
|
|
12
|
+
GenericDeploymentConfiguration,
|
|
13
|
+
signDeployFactory,
|
|
14
|
+
signGenericDeploy,
|
|
15
|
+
} from "../package/deployment";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
17
|
+
import { dirname } from "path";
|
|
18
|
+
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
const __dirname = dirname(__filename);
|
|
21
|
+
|
|
22
|
+
// Load environment variables from `.env.local`
|
|
23
|
+
dotenv.config({ path: path.resolve(__dirname, "../.env") });
|
|
24
|
+
|
|
25
|
+
type ChainConfig = {
|
|
26
|
+
chainId: number;
|
|
27
|
+
implementationAddress: Address;
|
|
28
|
+
owner: Address;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
async function signAndSaveSignatures({
|
|
32
|
+
turnkeyAccount,
|
|
33
|
+
chainConfigs,
|
|
34
|
+
proxyName,
|
|
35
|
+
}: {
|
|
36
|
+
turnkeyAccount: LocalAccount;
|
|
37
|
+
chainConfigs: ChainConfig[];
|
|
38
|
+
proxyName: "factoryProxy" | "premintExecutorProxy";
|
|
39
|
+
}) {
|
|
40
|
+
const configFolder = path.resolve(
|
|
41
|
+
__dirname,
|
|
42
|
+
`../deterministicConfig/${proxyName}/`
|
|
43
|
+
);
|
|
44
|
+
const configFile = path.join(configFolder, "params.json");
|
|
45
|
+
const deterministicDeployConfig = JSON.parse(
|
|
46
|
+
await readFile(configFile, "utf-8")
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const deploymentConfig: DeterministicDeploymentConfig = {
|
|
50
|
+
proxyDeployerAddress:
|
|
51
|
+
deterministicDeployConfig.proxyDeployerAddress as Address,
|
|
52
|
+
proxySalt: deterministicDeployConfig.proxySalt as ConfiguredSalt,
|
|
53
|
+
proxyShimSalt: deterministicDeployConfig.proxyShimSalt as ConfiguredSalt,
|
|
54
|
+
proxyCreationCode: deterministicDeployConfig.proxyCreationCode as Address,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const signedConfigs = await Promise.all(
|
|
58
|
+
chainConfigs.map(async (chainConfig) => {
|
|
59
|
+
return {
|
|
60
|
+
chainId: chainConfig.chainId,
|
|
61
|
+
signature: await signDeployFactory({
|
|
62
|
+
account: turnkeyAccount,
|
|
63
|
+
implementationAddress: chainConfig.implementationAddress,
|
|
64
|
+
owner: chainConfig.owner,
|
|
65
|
+
chainId: chainConfig.chainId,
|
|
66
|
+
deterministicDeploymentConfig: deploymentConfig,
|
|
67
|
+
}),
|
|
68
|
+
};
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// aggregate above to object of key value pair indexed by chain id as number:
|
|
73
|
+
const byChainId = signedConfigs.reduce((acc, { chainId, signature }) => {
|
|
74
|
+
acc[chainId] = signature;
|
|
75
|
+
return acc;
|
|
76
|
+
}, {} as { [key: number]: string });
|
|
77
|
+
|
|
78
|
+
// write as json to ../deterministicConfig/factoryDeploySignatures.json:
|
|
79
|
+
await writeFile(
|
|
80
|
+
path.join(configFolder, "signatures.json"),
|
|
81
|
+
JSON.stringify(byChainId, null, 2)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function signAndSaveUpgradeGate({
|
|
86
|
+
turnkeyAccount,
|
|
87
|
+
chainConfigs,
|
|
88
|
+
proxyName,
|
|
89
|
+
}: {
|
|
90
|
+
turnkeyAccount: LocalAccount;
|
|
91
|
+
chainConfigs: {
|
|
92
|
+
chainId: number;
|
|
93
|
+
owner: Address;
|
|
94
|
+
}[];
|
|
95
|
+
proxyName: "upgradeGate";
|
|
96
|
+
}) {
|
|
97
|
+
const configFolder = path.resolve(
|
|
98
|
+
__dirname,
|
|
99
|
+
`../deterministicConfig/${proxyName}/`
|
|
100
|
+
);
|
|
101
|
+
const configFile = path.join(configFolder, "params.json");
|
|
102
|
+
const deterministicDeployConfig = JSON.parse(
|
|
103
|
+
await readFile(configFile, "utf-8")
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const deploymentConfig: GenericDeploymentConfiguration = {
|
|
107
|
+
creationCode: deterministicDeployConfig.creationCode! as Hex,
|
|
108
|
+
salt: deterministicDeployConfig.salt! as Hex,
|
|
109
|
+
deployerAddress: deterministicDeployConfig.deployerAddress! as Address,
|
|
110
|
+
upgradeGateAddress:
|
|
111
|
+
deterministicDeployConfig.upgradeGateAddress! as Address,
|
|
112
|
+
proxyDeployerAddress:
|
|
113
|
+
deterministicDeployConfig.proxyDeployerAddress! as Address,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const upgradeGateAbi = parseAbi([
|
|
117
|
+
// ^? const abi: readonly [{ name: "balanceOf"; type: "function"; stateMutability:...
|
|
118
|
+
"function initialize(address owner)",
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
const signedConfigs = await Promise.all(
|
|
122
|
+
chainConfigs.map(async (chainConfig) => {
|
|
123
|
+
const initCall = encodeFunctionData({
|
|
124
|
+
abi: upgradeGateAbi,
|
|
125
|
+
functionName: "initialize",
|
|
126
|
+
args: [chainConfig.owner],
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
chainId: chainConfig.chainId,
|
|
131
|
+
signature: await signGenericDeploy({
|
|
132
|
+
account: turnkeyAccount,
|
|
133
|
+
chainId: chainConfig.chainId,
|
|
134
|
+
config: deploymentConfig,
|
|
135
|
+
initCall,
|
|
136
|
+
}),
|
|
137
|
+
};
|
|
138
|
+
})
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
// aggregate above to object of key value pair indexed by chain id as number:
|
|
142
|
+
const byChainId = signedConfigs.reduce((acc, { chainId, signature }) => {
|
|
143
|
+
acc[chainId] = signature;
|
|
144
|
+
return acc;
|
|
145
|
+
}, {} as { [key: number]: string });
|
|
146
|
+
|
|
147
|
+
// write as json to ../deterministicConfig/factoryDeploySignatures.json:
|
|
148
|
+
await writeFile(
|
|
149
|
+
path.join(configFolder, "signatures.json"),
|
|
150
|
+
JSON.stringify(byChainId, null, 2)
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const getChainConfigs = async () => {
|
|
155
|
+
const chainConfigsFiles = await glob(
|
|
156
|
+
path.resolve(__dirname, "../chainConfigs/*.json")
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const chainConfigs = await Promise.all(
|
|
160
|
+
chainConfigsFiles.map(async (chainConfigFile) => {
|
|
161
|
+
const chainId = parseInt(path.basename(chainConfigFile).split(".")[0]!);
|
|
162
|
+
|
|
163
|
+
// read file and process JSON contents:
|
|
164
|
+
const fileContents = await import(chainConfigFile);
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
chainId,
|
|
168
|
+
owner: fileContents["FACTORY_OWNER"]! as Address,
|
|
169
|
+
};
|
|
170
|
+
})
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
return chainConfigs;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const getFactoryImplConfigs = async () => {
|
|
177
|
+
const addresseFiles = await glob(
|
|
178
|
+
path.resolve(__dirname, "../addresses/*.json")
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
const chainConfigs = await Promise.all(
|
|
182
|
+
addresseFiles.map(async (addressConfigFile) => {
|
|
183
|
+
const chainId = parseInt(path.basename(addressConfigFile).split(".")[0]!);
|
|
184
|
+
|
|
185
|
+
// read file and process JSON contents:
|
|
186
|
+
const fileContents = await import(addressConfigFile);
|
|
187
|
+
|
|
188
|
+
// read chain config file as json, which is located at: ../chainConfigs/${chainId}.json:
|
|
189
|
+
const chainConfig = await import(
|
|
190
|
+
path.resolve(__dirname, `../chainConfigs/${chainId}.json`)
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
chainId,
|
|
195
|
+
implementationAddress: fileContents["FACTORY_IMPL"] as Address,
|
|
196
|
+
owner: chainConfig["FACTORY_OWNER"] as Address,
|
|
197
|
+
};
|
|
198
|
+
})
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
return chainConfigs;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const getPreminterImplConfigs = async () => {
|
|
205
|
+
const addresseFiles = await glob(
|
|
206
|
+
path.resolve(__dirname, "../addresses/*.json")
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const chainConfigs = await Promise.all(
|
|
210
|
+
addresseFiles.map(async (addressConfigFile) => {
|
|
211
|
+
const chainId = parseInt(path.basename(addressConfigFile).split(".")[0]!);
|
|
212
|
+
|
|
213
|
+
// read file and process JSON contents:
|
|
214
|
+
const fileContents = await import(addressConfigFile);
|
|
215
|
+
|
|
216
|
+
// read chain config file as json, which is located at: ../chainConfigs/${chainId}.json:
|
|
217
|
+
const chainConfig = await import(
|
|
218
|
+
path.resolve(__dirname, `../chainConfigs/${chainId}.json`)
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
chainId,
|
|
223
|
+
implementationAddress: fileContents["PREMINTER_IMPL"] as Address,
|
|
224
|
+
owner: chainConfig["FACTORY_OWNER"] as Address,
|
|
225
|
+
};
|
|
226
|
+
})
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
return chainConfigs.filter((x) => x.implementationAddress !== undefined);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
async function main() {
|
|
233
|
+
// Create a Turnkey HTTP client with API key credentials
|
|
234
|
+
const httpClient = new TurnkeyClient(
|
|
235
|
+
{
|
|
236
|
+
baseUrl: "https://api.turnkey.com",
|
|
237
|
+
},
|
|
238
|
+
// This uses API key credentials.
|
|
239
|
+
// If you're using passkeys, use `@turnkey/webauthn-stamper` to collect webauthn signatures:
|
|
240
|
+
new ApiKeyStamper({
|
|
241
|
+
apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY!,
|
|
242
|
+
apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY!,
|
|
243
|
+
})
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
// Create the Viem custom account
|
|
247
|
+
const turnkeyAccount = await createAccount({
|
|
248
|
+
client: httpClient,
|
|
249
|
+
organizationId: process.env.TURNKEY_ORGANIZATION_ID!,
|
|
250
|
+
privateKeyId: process.env.TURNKEY_PRIVATE_KEY_ID!,
|
|
251
|
+
// optional; will be fetched from Turnkey if not provided
|
|
252
|
+
ethereumAddress: process.env.TURNKEY_TARGET_ADDRESS!,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
await signAndSaveSignatures({
|
|
256
|
+
turnkeyAccount,
|
|
257
|
+
chainConfigs: await getFactoryImplConfigs(),
|
|
258
|
+
proxyName: "factoryProxy",
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
await signAndSaveSignatures({
|
|
262
|
+
turnkeyAccount,
|
|
263
|
+
chainConfigs: await getPreminterImplConfigs(),
|
|
264
|
+
proxyName: "premintExecutorProxy",
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
await signAndSaveUpgradeGate({
|
|
268
|
+
turnkeyAccount,
|
|
269
|
+
chainConfigs: await getChainConfigs(),
|
|
270
|
+
proxyName: "upgradeGate",
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
main().catch((error) => {
|
|
275
|
+
console.error(error);
|
|
276
|
+
process.exit(1);
|
|
277
|
+
});
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.17;
|
|
3
|
+
|
|
4
|
+
import "forge-std/Test.sol";
|
|
5
|
+
import {Zora1155Factory} from "@zoralabs/zora-1155-contracts/src/proxies/Zora1155Factory.sol";
|
|
6
|
+
import {ZoraDeployerUtils, Create2Deployment} from "@zoralabs/zora-1155-contracts/src/deployment/ZoraDeployerUtils.sol";
|
|
7
|
+
import {DeterministicProxyDeployer} from "@zoralabs/zora-1155-contracts/src/deployment/DeterministicProxyDeployer.sol";
|
|
8
|
+
import {ProxyShim} from "@zoralabs/zora-1155-contracts/src/utils/ProxyShim.sol";
|
|
9
|
+
import {UpgradeGate} from "@zoralabs/zora-1155-contracts/src/upgrades/UpgradeGate.sol";
|
|
10
|
+
import {Deployment, ChainConfig} from "@zoralabs/zora-1155-contracts/src/deployment/DeploymentConfig.sol";
|
|
11
|
+
import {IMinter1155} from "@zoralabs/zora-1155-contracts/src/interfaces/IMinter1155.sol";
|
|
12
|
+
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
|
|
13
|
+
import {DeterministicDeployerScript, DeterministicParams} from "@zoralabs/zora-1155-contracts/src/deployment/DeterministicDeployerScript.sol";
|
|
14
|
+
|
|
15
|
+
contract DeterministicProxyDeployerTest is DeterministicDeployerScript, Test {
|
|
16
|
+
using stdJson for string;
|
|
17
|
+
|
|
18
|
+
// the values in this test can be determined by running the script GetDeterministicParam.s.sol,
|
|
19
|
+
// and copying the output values here.
|
|
20
|
+
function _deployKnownZoraFactoryProxy(bytes32 salt) internal returns (DeterministicProxyDeployer) {
|
|
21
|
+
// create new factory deployer using ImmutableCreate2Factory
|
|
22
|
+
return DeterministicProxyDeployer(ZoraDeployerUtils.IMMUTABLE_CREATE2_FACTORY.safeCreate2(salt, type(DeterministicProxyDeployer).creationCode));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function create1155FactoryImpl() internal returns (address) {
|
|
26
|
+
address mintFeeRecipient = makeAddr("mintFeeRecipient");
|
|
27
|
+
address protocolRewards = makeAddr("protocolRewards");
|
|
28
|
+
|
|
29
|
+
(address factoryImplDeployment, , ) = ZoraDeployerUtils.deployNew1155AndFactoryImpl({
|
|
30
|
+
upgradeGateAddress: address(new UpgradeGate()),
|
|
31
|
+
mintFeeRecipient: mintFeeRecipient,
|
|
32
|
+
protocolRewards: protocolRewards,
|
|
33
|
+
merkleMinter: IMinter1155(address(0)),
|
|
34
|
+
redeemMinterFactory: IMinter1155(address(0)),
|
|
35
|
+
fixedPriceMinter: IMinter1155(address(0))
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return factoryImplDeployment;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function test_proxyCanByDeployedAtDesiredAddress(bytes32 proxySalt) external {
|
|
42
|
+
vm.createSelectFork("zora_goerli", 1252119);
|
|
43
|
+
// ensure nonce is greater than current account's nonce
|
|
44
|
+
|
|
45
|
+
(address deployerAddress, uint256 deployerPrivateKey) = makeAddrAndKey("deployer");
|
|
46
|
+
bytes32 proxyDeployerSalt = ZoraDeployerUtils.FACTORY_DEPLOYER_DEPLOYMENT_SALT;
|
|
47
|
+
|
|
48
|
+
// now we can create the implementation, pointing it to the expected deterministic address:
|
|
49
|
+
bytes32 proxyShimSalt = saltWithAddressInFirst20Bytes(deployerAddress, 10);
|
|
50
|
+
|
|
51
|
+
// 1. Create implementation contracts based on deterministic factory proxy address
|
|
52
|
+
|
|
53
|
+
// create 1155 and factory impl, we can know the deterministic factor proxy address ahead of time:
|
|
54
|
+
address factoryImplAddress = create1155FactoryImpl();
|
|
55
|
+
|
|
56
|
+
// 2. Create factory deployer at deterministic address
|
|
57
|
+
DeterministicProxyDeployer factoryProxyDeployer = _deployKnownZoraFactoryProxy(proxyDeployerSalt);
|
|
58
|
+
|
|
59
|
+
bytes memory factoryProxyCreationCode = type(Zora1155Factory).creationCode;
|
|
60
|
+
address mintFeeRecipient = makeAddr("mintFeeRecipient ");
|
|
61
|
+
|
|
62
|
+
bytes32 digest = factoryProxyDeployer.hashedDigestFactoryProxy(
|
|
63
|
+
proxyShimSalt,
|
|
64
|
+
proxySalt,
|
|
65
|
+
factoryProxyCreationCode,
|
|
66
|
+
factoryImplAddress,
|
|
67
|
+
mintFeeRecipient
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// sign the message
|
|
71
|
+
bytes memory signature = signAndMakeBytes(digest, deployerPrivateKey);
|
|
72
|
+
|
|
73
|
+
address expectedFactoryProxyAddress = ZoraDeployerUtils.deterministicFactoryProxyAddress(proxyShimSalt, proxySalt, address(factoryProxyDeployer));
|
|
74
|
+
|
|
75
|
+
// now do it as original deployer, it should succeed:
|
|
76
|
+
address factoryProxyAddress = factoryProxyDeployer.createFactoryProxyDeterministic(
|
|
77
|
+
proxyShimSalt,
|
|
78
|
+
proxySalt,
|
|
79
|
+
factoryProxyCreationCode,
|
|
80
|
+
expectedFactoryProxyAddress,
|
|
81
|
+
factoryImplAddress,
|
|
82
|
+
mintFeeRecipient,
|
|
83
|
+
signature
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// we know this salt from a script we ran that will generated
|
|
87
|
+
// create factory proxy, using deterministic address and known salt to get proper expected address:
|
|
88
|
+
assertEq(factoryProxyAddress, expectedFactoryProxyAddress, "factory proxy address wrong");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function signAndMakeBytes(bytes32 digest, uint256 privateKey) internal pure returns (bytes memory) {
|
|
92
|
+
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
|
|
93
|
+
|
|
94
|
+
// combine into a single bytes array
|
|
95
|
+
return abi.encodePacked(r, s, v);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function test_genericContractCanByDeployedAtDesiredAddress(uint32 nonce) external {
|
|
99
|
+
vm.createSelectFork("zora_goerli", 1252119);
|
|
100
|
+
|
|
101
|
+
(address deployerAddress, uint256 deployerPrivateKey) = makeAddrAndKey("deployer");
|
|
102
|
+
|
|
103
|
+
vm.assume(nonce > vm.getNonce(deployerAddress));
|
|
104
|
+
// we set the nonce to a random value, to prove this doesn't affect the deterministic addrss
|
|
105
|
+
vm.setNonce(deployerAddress, nonce);
|
|
106
|
+
|
|
107
|
+
DeterministicProxyDeployer factoryProxyDeployer = _deployKnownZoraFactoryProxy(bytes32(0));
|
|
108
|
+
|
|
109
|
+
address gateAdmin = makeAddr("gateAdmin");
|
|
110
|
+
|
|
111
|
+
bytes memory upgradeGateDeployCode = type(UpgradeGate).creationCode;
|
|
112
|
+
|
|
113
|
+
bytes memory initCall = abi.encodeWithSignature("initialize(address)", gateAdmin);
|
|
114
|
+
|
|
115
|
+
bytes32 genericTestDeploySalt = saltWithAddressInFirst20Bytes(deployerAddress, 20);
|
|
116
|
+
|
|
117
|
+
bytes32 digest = factoryProxyDeployer.hashedDigestGenericCreation(genericTestDeploySalt, upgradeGateDeployCode, initCall);
|
|
118
|
+
|
|
119
|
+
// sign the message
|
|
120
|
+
(uint8 v, bytes32 r, bytes32 s) = vm.sign(deployerPrivateKey, digest);
|
|
121
|
+
|
|
122
|
+
// combine into a single bytes array
|
|
123
|
+
bytes memory signature = abi.encodePacked(r, s, v);
|
|
124
|
+
|
|
125
|
+
factoryProxyDeployer.createAndInitGenericContractDeterministic(genericTestDeploySalt, upgradeGateDeployCode, initCall, signature);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.17;
|
|
3
|
+
|
|
4
|
+
import "forge-std/Test.sol";
|
|
5
|
+
import {IZoraCreator1155Factory} from "@zoralabs/zora-1155-contracts/src/interfaces/IZoraCreator1155Factory.sol";
|
|
6
|
+
import {ZoraCreator1155FactoryImpl} from "@zoralabs/zora-1155-contracts/src/factory/ZoraCreator1155FactoryImpl.sol";
|
|
7
|
+
import {IZoraCreator1155Errors} from "@zoralabs/zora-1155-contracts/src/interfaces/IZoraCreator1155Errors.sol";
|
|
8
|
+
import {IZoraCreator1155} from "@zoralabs/zora-1155-contracts/src/interfaces/IZoraCreator1155.sol";
|
|
9
|
+
import {ZoraCreator1155Impl} from "@zoralabs/zora-1155-contracts/src/nft/ZoraCreator1155Impl.sol";
|
|
10
|
+
import {IMinter1155} from "@zoralabs/zora-1155-contracts/src/interfaces/IMinter1155.sol";
|
|
11
|
+
import {IOwnable} from "@zoralabs/zora-1155-contracts/src/interfaces/IOwnable.sol";
|
|
12
|
+
import {ICreatorRoyaltiesControl} from "@zoralabs/zora-1155-contracts/src/interfaces/ICreatorRoyaltiesControl.sol";
|
|
13
|
+
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
|
|
14
|
+
import {ZoraCreatorFixedPriceSaleStrategy} from "@zoralabs/zora-1155-contracts/src/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.sol";
|
|
15
|
+
import {ForkDeploymentConfig, Deployment} from "@zoralabs/zora-1155-contracts/src/deployment/DeploymentConfig.sol";
|
|
16
|
+
|
|
17
|
+
contract ZoraCreator1155FactoryForkTest is ForkDeploymentConfig, Test {
|
|
18
|
+
uint256 constant quantityToMint = 3;
|
|
19
|
+
uint256 constant tokenMaxSupply = 100;
|
|
20
|
+
uint32 constant royaltyMintSchedule = 10;
|
|
21
|
+
uint32 constant royaltyBPS = 100;
|
|
22
|
+
uint256 constant mintFee = 0.000777 ether;
|
|
23
|
+
|
|
24
|
+
address collector;
|
|
25
|
+
address creator;
|
|
26
|
+
|
|
27
|
+
uint256 public constant PERMISSION_BIT_MINTER = 2 ** 2;
|
|
28
|
+
|
|
29
|
+
function setUp() external {
|
|
30
|
+
creator = vm.addr(1);
|
|
31
|
+
collector = vm.addr(2);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// @notice gets the chains to do fork tests on, by reading environment var FORK_TEST_CHAINS.
|
|
35
|
+
/// Chains are by name, and must match whats under `rpc_endpoints` in the foundry.toml
|
|
36
|
+
function getForkTestChains() private view returns (string[] memory result) {
|
|
37
|
+
try vm.envString("FORK_TEST_CHAINS", ",") returns (string[] memory forkTestChains) {
|
|
38
|
+
result = forkTestChains;
|
|
39
|
+
} catch {
|
|
40
|
+
console.log("could not get fork test chains - make sure the environment variable FORK_TEST_CHAINS is set");
|
|
41
|
+
result = new string[](0);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function _setupToken(IZoraCreator1155 target, IMinter1155 fixedPrice, uint96 tokenPrice) private returns (uint256 tokenId) {
|
|
46
|
+
string memory tokenURI = "ipfs://token";
|
|
47
|
+
|
|
48
|
+
tokenId = target.setupNewToken(tokenURI, tokenMaxSupply);
|
|
49
|
+
|
|
50
|
+
target.addPermission(tokenId, address(fixedPrice), PERMISSION_BIT_MINTER);
|
|
51
|
+
|
|
52
|
+
target.callSale(
|
|
53
|
+
tokenId,
|
|
54
|
+
fixedPrice,
|
|
55
|
+
abi.encodeWithSelector(
|
|
56
|
+
ZoraCreatorFixedPriceSaleStrategy.setSale.selector,
|
|
57
|
+
tokenId,
|
|
58
|
+
ZoraCreatorFixedPriceSaleStrategy.SalesConfig({
|
|
59
|
+
pricePerToken: tokenPrice,
|
|
60
|
+
saleStart: 0,
|
|
61
|
+
saleEnd: type(uint64).max,
|
|
62
|
+
maxTokensPerAddress: 0,
|
|
63
|
+
fundsRecipient: address(0)
|
|
64
|
+
})
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function _createErc1155Contract(IZoraCreator1155Factory factory) private returns (IZoraCreator1155 target) {
|
|
70
|
+
// create the contract, with no toekns
|
|
71
|
+
bytes[] memory initSetup = new bytes[](0);
|
|
72
|
+
|
|
73
|
+
address admin = creator;
|
|
74
|
+
string memory contractURI = "ipfs://asdfasdf";
|
|
75
|
+
string memory name = "Test";
|
|
76
|
+
address royaltyRecipient = creator;
|
|
77
|
+
|
|
78
|
+
address deployedAddress = factory.createContract(
|
|
79
|
+
contractURI,
|
|
80
|
+
name,
|
|
81
|
+
ICreatorRoyaltiesControl.RoyaltyConfiguration({
|
|
82
|
+
royaltyBPS: royaltyBPS,
|
|
83
|
+
royaltyRecipient: royaltyRecipient,
|
|
84
|
+
royaltyMintSchedule: royaltyMintSchedule
|
|
85
|
+
}),
|
|
86
|
+
payable(admin),
|
|
87
|
+
initSetup
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
target = IZoraCreator1155(deployedAddress);
|
|
91
|
+
|
|
92
|
+
// ** 2. Setup a new token with the fixed price sales strategy **
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function mintTokenAtFork(IZoraCreator1155Factory factory) internal {
|
|
96
|
+
uint96 tokenPrice = 1 ether;
|
|
97
|
+
IMinter1155 fixedPrice = factory.defaultMinters()[0];
|
|
98
|
+
// now create a contract with the factory
|
|
99
|
+
vm.startPrank(creator);
|
|
100
|
+
|
|
101
|
+
// ** 1. Create the erc1155 contract **
|
|
102
|
+
IZoraCreator1155 target = _createErc1155Contract(factory);
|
|
103
|
+
|
|
104
|
+
// ** 2. Setup a new token with the fixed price sales strategy and the token price **
|
|
105
|
+
uint256 tokenId = _setupToken(target, fixedPrice, tokenPrice);
|
|
106
|
+
|
|
107
|
+
// ** 3. Mint on that contract **
|
|
108
|
+
|
|
109
|
+
// mint 3 tokens
|
|
110
|
+
uint256 valueToSend = quantityToMint * (tokenPrice + mintFee);
|
|
111
|
+
|
|
112
|
+
// mint the token
|
|
113
|
+
vm.deal(collector, valueToSend);
|
|
114
|
+
vm.startPrank(collector);
|
|
115
|
+
ZoraCreator1155Impl(address(target)).mintWithRewards{value: valueToSend}(fixedPrice, tokenId, quantityToMint, abi.encode(collector), address(0));
|
|
116
|
+
|
|
117
|
+
uint256 balance = ZoraCreator1155Impl(address(target)).balanceOf(collector, tokenId);
|
|
118
|
+
|
|
119
|
+
assertEq(balance, quantityToMint, "balance mismatch");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function testTheFork(string memory chainName) private {
|
|
123
|
+
console.log("testing on fork: ", chainName);
|
|
124
|
+
|
|
125
|
+
// create and select the fork, which will be used for all subsequent calls
|
|
126
|
+
// it will also affect the current block chain id based on the rpc url returned
|
|
127
|
+
vm.createSelectFork(vm.rpcUrl(chainName));
|
|
128
|
+
|
|
129
|
+
Deployment memory deployment = getDeployment();
|
|
130
|
+
|
|
131
|
+
address factoryAddress = deployment.factoryProxy;
|
|
132
|
+
ZoraCreator1155FactoryImpl factory = ZoraCreator1155FactoryImpl(factoryAddress);
|
|
133
|
+
|
|
134
|
+
assertEq(factory.implementation(), deployment.factoryImpl, "factory implementation incorrect");
|
|
135
|
+
|
|
136
|
+
assertEq(getChainConfig().factoryOwner, IOwnable(factoryAddress).owner(), string.concat("configured owner incorrect on: ", chainName));
|
|
137
|
+
|
|
138
|
+
// make sure that the address from the factory matches the stored fixed price address
|
|
139
|
+
// sanity check - check minters match config
|
|
140
|
+
assertEq(address(factory.merkleMinter()), deployment.merkleMintSaleStrategy, "merkle minter incorrect");
|
|
141
|
+
assertEq(address(factory.fixedPriceMinter()), deployment.fixedPriceSaleStrategy, "fixed priced minter incorrect");
|
|
142
|
+
assertEq(address(factory.redeemMinterFactory()), deployment.redeemMinterFactory, "redeem minter not correct");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function test_fork_canCreateContractAndMint() external {
|
|
146
|
+
string[] memory forkTestChains = getForkTestChains();
|
|
147
|
+
for (uint256 i = 0; i < forkTestChains.length; i++) {
|
|
148
|
+
testTheFork(forkTestChains[i]);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.17;
|
|
3
|
+
|
|
4
|
+
import "forge-std/Test.sol";
|
|
5
|
+
import {ForkDeploymentConfig} from "@zoralabs/zora-1155-contracts/src/deployment/DeploymentConfig.sol";
|
|
6
|
+
import {ZoraCreator1155Attribution, ContractCreationConfig, PremintConfig, TokenCreationConfig} from "@zoralabs/zora-1155-contracts/src/delegation/ZoraCreator1155Attribution.sol";
|
|
7
|
+
import {ZoraCreator1155PremintExecutorImpl} from "@zoralabs/zora-1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImpl.sol";
|
|
8
|
+
import {ZoraCreator1155FactoryImpl} from "@zoralabs/zora-1155-contracts/src/factory/ZoraCreator1155FactoryImpl.sol";
|
|
9
|
+
|
|
10
|
+
contract ZoraCreator1155PreminterForkTest is ForkDeploymentConfig, Test {
|
|
11
|
+
ZoraCreator1155FactoryImpl factory;
|
|
12
|
+
ZoraCreator1155PremintExecutorImpl preminter;
|
|
13
|
+
uint256 mintFeeAmount = 0.000777 ether;
|
|
14
|
+
|
|
15
|
+
/// @notice gets the chains to do fork tests on, by reading environment var FORK_TEST_CHAINS.
|
|
16
|
+
/// Chains are by name, and must match whats under `rpc_endpoints` in the foundry.toml
|
|
17
|
+
function getForkTestChains() private view returns (string[] memory result) {
|
|
18
|
+
try vm.envString("FORK_TEST_CHAINS", ",") returns (string[] memory forkTestChains) {
|
|
19
|
+
result = forkTestChains;
|
|
20
|
+
} catch {
|
|
21
|
+
console.log("could not get fork test chains - make sure the environment variable FORK_TEST_CHAINS is set");
|
|
22
|
+
result = new string[](0);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function testTheForkPremint(string memory chainName) private {
|
|
27
|
+
console.log("testing on fork: ", chainName);
|
|
28
|
+
|
|
29
|
+
// create and select the fork, which will be used for all subsequent calls
|
|
30
|
+
// it will also affect the current block chain id based on the rpc url returned
|
|
31
|
+
vm.createSelectFork(vm.rpcUrl(chainName));
|
|
32
|
+
|
|
33
|
+
// get contract hash, which is unique per contract creation config, and can be used
|
|
34
|
+
// retreive the address created for a contract
|
|
35
|
+
address preminterAddress = getDeployment().preminterProxy;
|
|
36
|
+
|
|
37
|
+
if (preminterAddress == address(0)) {
|
|
38
|
+
console.log("preminter not configured for chain...skipping");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// override local preminter to use the addresses from the chain
|
|
43
|
+
factory = ZoraCreator1155FactoryImpl(getDeployment().factoryProxy);
|
|
44
|
+
preminter = ZoraCreator1155PremintExecutorImpl(preminterAddress);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function test_fork_successfullyMintsTokens() external {
|
|
48
|
+
string[] memory forkTestChains = getForkTestChains();
|
|
49
|
+
for (uint256 i = 0; i < forkTestChains.length; i++) {
|
|
50
|
+
testTheForkPremint(forkTestChains[i]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function _signAndExecutePremint(
|
|
55
|
+
ContractCreationConfig memory contractConfig,
|
|
56
|
+
PremintConfig memory premintConfig,
|
|
57
|
+
uint256 privateKey,
|
|
58
|
+
uint256 chainId,
|
|
59
|
+
address executor,
|
|
60
|
+
uint256 quantityToMint,
|
|
61
|
+
string memory comment
|
|
62
|
+
) private returns (uint256 newTokenId) {
|
|
63
|
+
bytes memory signature = _signPremint(preminter.getContractAddress(contractConfig), premintConfig, privateKey, chainId);
|
|
64
|
+
|
|
65
|
+
uint256 mintCost = mintFeeAmount * quantityToMint;
|
|
66
|
+
vm.deal(executor, mintCost);
|
|
67
|
+
|
|
68
|
+
// now call the premint function, using the same config that was used to generate the digest, and the signature
|
|
69
|
+
vm.prank(executor);
|
|
70
|
+
newTokenId = preminter.premint{value: mintCost}(contractConfig, premintConfig, signature, quantityToMint, comment);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function _signPremint(
|
|
74
|
+
address contractAddress,
|
|
75
|
+
PremintConfig memory premintConfig,
|
|
76
|
+
uint256 privateKey,
|
|
77
|
+
uint256 chainId
|
|
78
|
+
) private pure returns (bytes memory) {
|
|
79
|
+
bytes32 digest = ZoraCreator1155Attribution.premintHashedTypeDataV4(premintConfig, contractAddress, chainId);
|
|
80
|
+
|
|
81
|
+
// 3. Sign the digest
|
|
82
|
+
// create a signature with the digest for the params
|
|
83
|
+
return _sign(privateKey, digest);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function _sign(uint256 privateKey, bytes32 digest) private pure returns (bytes memory) {
|
|
87
|
+
// sign the message
|
|
88
|
+
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
|
|
89
|
+
|
|
90
|
+
// combine into a single bytes array
|
|
91
|
+
return abi.encodePacked(r, s, v);
|
|
92
|
+
}
|
|
93
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"allowJs": true,
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"downlevelIteration": true,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"isolatedModules": true,
|
|
8
|
+
"lib": ["es2021"],
|
|
9
|
+
"module": "esnext",
|
|
10
|
+
"moduleResolution": "node",
|
|
11
|
+
"noImplicitAny": true,
|
|
12
|
+
"noUncheckedIndexedAccess": true,
|
|
13
|
+
"noUnusedLocals": true,
|
|
14
|
+
"noUnusedParameters": true,
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"skipLibCheck": true,
|
|
17
|
+
"strict": true,
|
|
18
|
+
"strictNullChecks": true,
|
|
19
|
+
"target": "es2021",
|
|
20
|
+
"types": ["node"],
|
|
21
|
+
"outDir": "dist"
|
|
22
|
+
},
|
|
23
|
+
"exclude": ["node_modules/**", "dist/**"],
|
|
24
|
+
"include": ["package/**/*.ts", "script/*.ts"]
|
|
25
|
+
}
|
package/tsup.config.ts
ADDED