@aztec/ethereum 0.48.0 → 0.50.1

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.
@@ -95,6 +95,7 @@ export declare const deployL1Contracts: (rpcUrl: string, account: HDAccount | Pr
95
95
  l2FeeJuiceAddress: AztecAddress;
96
96
  vkTreeRoot: Fr;
97
97
  assumeProvenUntil?: number;
98
+ salt: number | undefined;
98
99
  }) => Promise<DeployL1Contracts>;
99
100
  /**
100
101
  * Helper function to deploy ETH contracts.
@@ -105,5 +106,5 @@ export declare const deployL1Contracts: (rpcUrl: string, account: HDAccount | Pr
105
106
  * @param args - Constructor arguments for the contract.
106
107
  * @returns The ETH address the contract was deployed to.
107
108
  */
108
- export declare function deployL1Contract(walletClient: WalletClient<HttpTransport, Chain, Account>, publicClient: PublicClient<HttpTransport, Chain>, abi: Narrow<Abi | readonly unknown[]>, bytecode: Hex, args?: readonly unknown[]): Promise<EthAddress>;
109
+ export declare function deployL1Contract(walletClient: WalletClient<HttpTransport, Chain, Account>, publicClient: PublicClient<HttpTransport, Chain>, abi: Narrow<Abi | readonly unknown[]>, bytecode: Hex, args?: readonly unknown[], maybeSalt?: Hex, logger?: DebugLogger): Promise<EthAddress>;
109
110
  //# sourceMappingURL=deploy_l1_contracts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deploy_l1_contracts.d.ts","sourceRoot":"","sources":["../src/deploy_l1_contracts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,KAAK,EACV,KAAK,GAAG,EACR,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,EAMlB,MAAM,MAAM,CAAC;AACd,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,iBAAiB,EAA0C,MAAM,eAAe,CAAC;AAG/G,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEtE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;OAEG;IACH,YAAY,EAAE,YAAY,CAAC,aAAa,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAC1D;;OAEG;IACH,YAAY,EAAE,YAAY,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACjD;;OAEG;IACH,mBAAmB,EAAE,mBAAmB,CAAC;CAC1C,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC,GAAG,GAAG,SAAS,OAAO,EAAE,CAAC,CAAC;IAC9C;;OAEG;IACH,gBAAgB,EAAE,GAAG,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C;;OAEG;IACH,KAAK,EAAE,iBAAiB,CAAC;IACzB;;OAEG;IACH,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;OAEG;IACH,kBAAkB,EAAE,iBAAiB,CAAC;IACtC;;OAEG;IACH,QAAQ,EAAE,iBAAiB,CAAC;IAC5B;;OAEG;IACH,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;OAEG;IACH,QAAQ,EAAE,iBAAiB,CAAC;IAC5B;;OAEG;IACH,cAAc,EAAE,iBAAiB,CAAC;CACnC;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,YAAY,EAAE,YAAY,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACjD,YAAY,EAAE,YAAY,CAAC,aAAa,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;CAC3D,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,+BAA+B,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,GAAG,SAAS,GAAG,iBAAiB,EACvF,KAAK,GAAE,KAAe,GACrB,SAAS,CAmBX;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,WACpB,MAAM,WACL,SAAS,GAAG,iBAAiB,SAC/B,KAAK,UACJ,WAAW,qBACA,gCAAgC,QAC7C;IAAE,iBAAiB,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,EAAE,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,KACpF,QAAQ,iBAAiB,CAyK3B,CAAC;AAGF;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,YAAY,EAAE,YAAY,CAAC,aAAa,EAAE,KAAK,EAAE,OAAO,CAAC,EACzD,YAAY,EAAE,YAAY,CAAC,aAAa,EAAE,KAAK,CAAC,EAChD,GAAG,EAAE,MAAM,CAAC,GAAG,GAAG,SAAS,OAAO,EAAE,CAAC,EACrC,QAAQ,EAAE,GAAG,EACb,IAAI,GAAE,SAAS,OAAO,EAAO,GAC5B,OAAO,CAAC,UAAU,CAAC,CAkBrB"}
1
+ {"version":3,"file":"deploy_l1_contracts.d.ts","sourceRoot":"","sources":["../src/deploy_l1_contracts.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { EthAddress } from '@aztec/foundation/eth-address';
2
- import { createPublicClient, createWalletClient, getAddress, getContract, http, } from 'viem';
2
+ import { concatHex, createPublicClient, createWalletClient, encodeDeployData, getAddress, getContract, getContractAddress, http, numberToHex, padHex, zeroAddress, } from 'viem';
3
3
  import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
4
4
  import { foundry } from 'viem/chains';
5
5
  /**
@@ -55,27 +55,55 @@ export const deployL1Contracts = async (rpcUrl, account, chain, logger, contract
55
55
  throw new Error(`Error setting block interval: ${res.error.message}`);
56
56
  }
57
57
  logger.info(`Set block interval to ${interval}`);
58
- logger.debug('Deploying contracts...');
59
- const walletClient = createWalletClient({
60
- account,
61
- chain,
62
- transport: http(rpcUrl),
63
- });
64
- const publicClient = createPublicClient({
65
- chain,
66
- transport: http(rpcUrl),
67
- });
68
- const registryAddress = await deployL1Contract(walletClient, publicClient, contractsToDeploy.registry.contractAbi, contractsToDeploy.registry.contractBytecode);
58
+ logger.info(`Deploying contracts from ${account.address.toString()}...`);
59
+ const walletClient = createWalletClient({ account, chain, transport: http(rpcUrl) });
60
+ const publicClient = createPublicClient({ chain, transport: http(rpcUrl) });
61
+ const deployer = new L1Deployer(walletClient, publicClient, args.salt, logger);
62
+ const registryAddress = await deployer.deploy(contractsToDeploy.registry, [account.address.toString()]);
69
63
  logger.info(`Deployed Registry at ${registryAddress}`);
70
- const availabilityOracleAddress = await deployL1Contract(walletClient, publicClient, contractsToDeploy.availabilityOracle.contractAbi, contractsToDeploy.availabilityOracle.contractBytecode);
64
+ const availabilityOracleAddress = await deployer.deploy(contractsToDeploy.availabilityOracle);
71
65
  logger.info(`Deployed AvailabilityOracle at ${availabilityOracleAddress}`);
72
- const feeJuiceAddress = await deployL1Contract(walletClient, publicClient, contractsToDeploy.feeJuice.contractAbi, contractsToDeploy.feeJuice.contractBytecode);
66
+ const feeJuiceAddress = await deployer.deploy(contractsToDeploy.feeJuice);
73
67
  logger.info(`Deployed Fee Juice at ${feeJuiceAddress}`);
74
- const rollupAddress = await deployL1Contract(walletClient, publicClient, contractsToDeploy.rollup.contractAbi, contractsToDeploy.rollup.contractBytecode, [
68
+ const feeJuicePortalAddress = await deployer.deploy(contractsToDeploy.feeJuicePortal, [account.address.toString()]);
69
+ logger.info(`Deployed Gas Portal at ${feeJuicePortalAddress}`);
70
+ const feeJuicePortal = getContract({
71
+ address: feeJuicePortalAddress.toString(),
72
+ abi: contractsToDeploy.feeJuicePortal.contractAbi,
73
+ client: walletClient,
74
+ });
75
+ // fund the portal contract with Fee Juice
76
+ const feeJuice = getContract({
77
+ address: feeJuiceAddress.toString(),
78
+ abi: contractsToDeploy.feeJuice.contractAbi,
79
+ client: walletClient,
80
+ });
81
+ // @note This value MUST match what is in `constants.nr`. It is currently specified here instead of just importing
82
+ // because there is circular dependency hell. This is a temporary solution. #3342
83
+ const FEE_JUICE_INITIAL_MINT = 20000000000;
84
+ const receipt = await feeJuice.write.mint([feeJuicePortalAddress.toString(), FEE_JUICE_INITIAL_MINT], {});
85
+ await publicClient.waitForTransactionReceipt({ hash: receipt });
86
+ logger.info(`Funded fee juice portal contract with Fee Juice`);
87
+ if ((await feeJuicePortal.read.registry([])) === zeroAddress) {
88
+ await publicClient.waitForTransactionReceipt({
89
+ hash: await feeJuicePortal.write.initialize([
90
+ registryAddress.toString(),
91
+ feeJuiceAddress.toString(),
92
+ args.l2FeeJuiceAddress.toString(),
93
+ ]),
94
+ });
95
+ logger.verbose(`Fee juice portal initialized with registry ${registryAddress.toString()}`);
96
+ }
97
+ else {
98
+ logger.verbose(`Fee juice portal is already initialized`);
99
+ }
100
+ logger.info(`Initialized Gas Portal at ${feeJuicePortalAddress} to bridge between L1 ${feeJuiceAddress} to L2 ${args.l2FeeJuiceAddress}`);
101
+ const rollupAddress = await deployer.deploy(contractsToDeploy.rollup, [
75
102
  getAddress(registryAddress.toString()),
76
103
  getAddress(availabilityOracleAddress.toString()),
77
- getAddress(feeJuiceAddress.toString()),
104
+ getAddress(feeJuicePortalAddress.toString()),
78
105
  args.vkTreeRoot.toString(),
106
+ account.address.toString(),
79
107
  ]);
80
108
  logger.info(`Deployed Rollup at ${rollupAddress}`);
81
109
  // Set initial blocks as proven if requested
@@ -115,32 +143,13 @@ export const deployL1Contracts = async (rpcUrl, account, chain, logger, contract
115
143
  abi: contractsToDeploy.registry.contractAbi,
116
144
  client: walletClient,
117
145
  });
118
- await registryContract.write.upgrade([getAddress(rollupAddress.toString()), getAddress(inboxAddress.toString()), getAddress(outboxAddress.toString())], { account });
119
- // this contract remains uninitialized because at this point we don't know the address of the Fee Juice on L2
120
- const feeJuicePortalAddress = await deployL1Contract(walletClient, publicClient, contractsToDeploy.feeJuicePortal.contractAbi, contractsToDeploy.feeJuicePortal.contractBytecode);
121
- logger.info(`Deployed Gas Portal at ${feeJuicePortalAddress}`);
122
- const feeJuicePortal = getContract({
123
- address: feeJuicePortalAddress.toString(),
124
- abi: contractsToDeploy.feeJuicePortal.contractAbi,
125
- client: walletClient,
126
- });
127
- await publicClient.waitForTransactionReceipt({
128
- hash: await feeJuicePortal.write.initialize([
129
- registryAddress.toString(),
130
- feeJuiceAddress.toString(),
131
- args.l2FeeJuiceAddress.toString(),
132
- ]),
133
- });
134
- logger.info(`Initialized Gas Portal at ${feeJuicePortalAddress} to bridge between L1 ${feeJuiceAddress} to L2 ${args.l2FeeJuiceAddress}`);
135
- // fund the rollup contract with Fee Juice
136
- const feeJuice = getContract({
137
- address: feeJuiceAddress.toString(),
138
- abi: contractsToDeploy.feeJuice.contractAbi,
139
- client: walletClient,
140
- });
141
- const receipt = await feeJuice.write.mint([rollupAddress.toString(), 100000000000000000000n], {});
142
- await publicClient.waitForTransactionReceipt({ hash: receipt });
143
- logger.info(`Funded rollup contract with Fee Juice`);
146
+ if (!(await registryContract.read.isRollupRegistered([getAddress(rollupAddress.toString())]))) {
147
+ await registryContract.write.upgrade([getAddress(rollupAddress.toString())], { account });
148
+ logger.verbose(`Upgraded registry contract at ${registryAddress} to rollup ${rollupAddress}`);
149
+ }
150
+ else {
151
+ logger.verbose(`Registry ${registryAddress} has already registered rollup ${rollupAddress}`);
152
+ }
144
153
  const l1Contracts = {
145
154
  availabilityOracleAddress,
146
155
  rollupAddress,
@@ -156,6 +165,17 @@ export const deployL1Contracts = async (rpcUrl, account, chain, logger, contract
156
165
  l1ContractAddresses: l1Contracts,
157
166
  };
158
167
  };
168
+ class L1Deployer {
169
+ constructor(walletClient, publicClient, maybeSalt, logger) {
170
+ this.walletClient = walletClient;
171
+ this.publicClient = publicClient;
172
+ this.logger = logger;
173
+ this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), { size: 32 }) : undefined;
174
+ }
175
+ deploy(params, args = []) {
176
+ return deployL1Contract(this.walletClient, this.publicClient, params.contractAbi, params.contractBytecode, args, this.salt, this.logger);
177
+ }
178
+ }
159
179
  // docs:start:deployL1Contract
160
180
  /**
161
181
  * Helper function to deploy ETH contracts.
@@ -166,18 +186,36 @@ export const deployL1Contracts = async (rpcUrl, account, chain, logger, contract
166
186
  * @param args - Constructor arguments for the contract.
167
187
  * @returns The ETH address the contract was deployed to.
168
188
  */
169
- export async function deployL1Contract(walletClient, publicClient, abi, bytecode, args = []) {
170
- const hash = await walletClient.deployContract({
171
- abi,
172
- bytecode,
173
- args,
174
- });
175
- const receipt = await publicClient.waitForTransactionReceipt({ hash, pollingInterval: 100 });
176
- const contractAddress = receipt.contractAddress;
177
- if (!contractAddress) {
178
- throw new Error(`No contract address found in receipt: ${JSON.stringify(receipt, (_, val) => typeof val === 'bigint' ? String(val) : val)}`);
189
+ export async function deployL1Contract(walletClient, publicClient, abi, bytecode, args = [], maybeSalt, logger) {
190
+ if (maybeSalt) {
191
+ const salt = padHex(maybeSalt, { size: 32 });
192
+ const deployer = '0x4e59b44847b379578588920cA78FbF26c0B4956C';
193
+ const calldata = encodeDeployData({ abi, bytecode, args });
194
+ const address = getContractAddress({ from: deployer, salt, bytecode: calldata, opcode: 'CREATE2' });
195
+ const existing = await publicClient.getBytecode({ address });
196
+ if (existing === undefined || existing === '0x') {
197
+ const hash = await walletClient.sendTransaction({
198
+ to: deployer,
199
+ data: concatHex([salt, calldata]),
200
+ });
201
+ logger?.verbose(`Deploying contract with salt ${salt} to address ${address} in tx ${hash}`);
202
+ await publicClient.waitForTransactionReceipt({ hash, pollingInterval: 100 });
203
+ }
204
+ else {
205
+ logger?.verbose(`Skipping existing deployment of contract with salt ${salt} to address ${address}`);
206
+ }
207
+ return EthAddress.fromString(address);
208
+ }
209
+ else {
210
+ const hash = await walletClient.deployContract({ abi, bytecode, args });
211
+ logger?.verbose(`Deploying contract in tx ${hash}`);
212
+ const receipt = await publicClient.waitForTransactionReceipt({ hash, pollingInterval: 100 });
213
+ const contractAddress = receipt.contractAddress;
214
+ if (!contractAddress) {
215
+ throw new Error(`No contract address found in receipt: ${JSON.stringify(receipt, (_, val) => typeof val === 'bigint' ? String(val) : val)}`);
216
+ }
217
+ return EthAddress.fromString(contractAddress);
179
218
  }
180
- return EthAddress.fromString(receipt.contractAddress);
181
219
  }
182
220
  // docs:end:deployL1Contract
183
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95X2wxX2NvbnRyYWN0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9kZXBsb3lfbDFfY29udHJhY3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUszRCxPQUFPLEVBT0wsa0JBQWtCLEVBQ2xCLGtCQUFrQixFQUNsQixVQUFVLEVBQ1YsV0FBVyxFQUNYLElBQUksR0FDTCxNQUFNLE1BQU0sQ0FBQztBQUNkLE9BQU8sRUFBMEMsaUJBQWlCLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDL0csT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQTJFdEM7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FDN0IsTUFBYyxFQUNkLCtCQUF1RixFQUN2RixRQUFlLE9BQU87SUFFdEIsTUFBTSxTQUFTLEdBQ2IsT0FBTywrQkFBK0IsS0FBSyxRQUFRO1FBQ2pELENBQUMsQ0FBQywrQkFBK0IsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDO1lBQ2hELENBQUMsQ0FBQyxtQkFBbUIsQ0FBQywrQkFBZ0QsQ0FBQztZQUN2RSxDQUFDLENBQUMsaUJBQWlCLENBQUMsK0JBQStCLENBQUM7UUFDdEQsQ0FBQyxDQUFDLCtCQUErQixDQUFDO0lBRXRDLE1BQU0sWUFBWSxHQUFHLGtCQUFrQixDQUFDO1FBQ3RDLE9BQU8sRUFBRSxTQUFTO1FBQ2xCLEtBQUs7UUFDTCxTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQztLQUN4QixDQUFDLENBQUM7SUFDSCxNQUFNLFlBQVksR0FBRyxrQkFBa0IsQ0FBQztRQUN0QyxLQUFLO1FBQ0wsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUM7S0FDeEIsQ0FBQyxDQUFDO0lBRUgsT0FBTyxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsQ0FBQztBQUN4QyxDQUFDO0FBRUQ7Ozs7Ozs7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
221
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95X2wxX2NvbnRyYWN0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9kZXBsb3lfbDFfY29udHJhY3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUszRCxPQUFPLEVBT0wsU0FBUyxFQUNULGtCQUFrQixFQUNsQixrQkFBa0IsRUFDbEIsZ0JBQWdCLEVBQ2hCLFVBQVUsRUFDVixXQUFXLEVBQ1gsa0JBQWtCLEVBQ2xCLElBQUksRUFDSixXQUFXLEVBQ1gsTUFBTSxFQUNOLFdBQVcsR0FDWixNQUFNLE1BQU0sQ0FBQztBQUNkLE9BQU8sRUFBMEMsaUJBQWlCLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDL0csT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQTJFdEM7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FDN0IsTUFBYyxFQUNkLCtCQUF1RixFQUN2RixRQUFlLE9BQU87SUFFdEIsTUFBTSxTQUFTLEdBQ2IsT0FBTywrQkFBK0IsS0FBSyxRQUFRO1FBQ2pELENBQUMsQ0FBQywrQkFBK0IsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDO1lBQ2hELENBQUMsQ0FBQyxtQkFBbUIsQ0FBQywrQkFBZ0QsQ0FBQztZQUN2RSxDQUFDLENBQUMsaUJBQWlCLENBQUMsK0JBQStCLENBQUM7UUFDdEQsQ0FBQyxDQUFDLCtCQUErQixDQUFDO0lBRXRDLE1BQU0sWUFBWSxHQUFHLGtCQUFrQixDQUFDO1FBQ3RDLE9BQU8sRUFBRSxTQUFTO1FBQ2xCLEtBQUs7UUFDTCxTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQztLQUN4QixDQUFDLENBQUM7SUFDSCxNQUFNLFlBQVksR0FBRyxrQkFBa0IsQ0FBQztRQUN0QyxLQUFLO1FBQ0wsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUM7S0FDeEIsQ0FBQyxD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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/ethereum",
3
- "version": "0.48.0",
3
+ "version": "0.50.1",
4
4
  "type": "module",
5
5
  "exports": "./dest/index.js",
6
6
  "typedocOptions": {
@@ -24,7 +24,7 @@
24
24
  "../package.common.json"
25
25
  ],
26
26
  "dependencies": {
27
- "@aztec/foundation": "0.48.0",
27
+ "@aztec/foundation": "0.50.1",
28
28
  "dotenv": "^16.0.3",
29
29
  "tslib": "^2.4.0",
30
30
  "viem": "^2.7.15"
@@ -11,11 +11,17 @@ import {
11
11
  type HttpTransport,
12
12
  type PublicClient,
13
13
  type WalletClient,
14
+ concatHex,
14
15
  createPublicClient,
15
16
  createWalletClient,
17
+ encodeDeployData,
16
18
  getAddress,
17
19
  getContract,
20
+ getContractAddress,
18
21
  http,
22
+ numberToHex,
23
+ padHex,
24
+ zeroAddress,
19
25
  } from 'viem';
20
26
  import { type HDAccount, type PrivateKeyAccount, mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
21
27
  import { foundry } from 'viem/chains';
@@ -141,7 +147,7 @@ export const deployL1Contracts = async (
141
147
  chain: Chain,
142
148
  logger: DebugLogger,
143
149
  contractsToDeploy: L1ContractArtifactsForDeployment,
144
- args: { l2FeeJuiceAddress: AztecAddress; vkTreeRoot: Fr; assumeProvenUntil?: number },
150
+ args: { l2FeeJuiceAddress: AztecAddress; vkTreeRoot: Fr; assumeProvenUntil?: number; salt: number | undefined },
145
151
  ): Promise<DeployL1Contracts> => {
146
152
  // We are assuming that you are running this on a local anvil node which have 1s block times
147
153
  // To align better with actual deployment, we update the block interval to 12s
@@ -162,55 +168,70 @@ export const deployL1Contracts = async (
162
168
  }
163
169
  logger.info(`Set block interval to ${interval}`);
164
170
 
165
- logger.debug('Deploying contracts...');
171
+ logger.info(`Deploying contracts from ${account.address.toString()}...`);
166
172
 
167
- const walletClient = createWalletClient({
168
- account,
169
- chain,
170
- transport: http(rpcUrl),
171
- });
172
- const publicClient = createPublicClient({
173
- chain,
174
- transport: http(rpcUrl),
175
- });
173
+ const walletClient = createWalletClient({ account, chain, transport: http(rpcUrl) });
174
+ const publicClient = createPublicClient({ chain, transport: http(rpcUrl) });
175
+ const deployer = new L1Deployer(walletClient, publicClient, args.salt, logger);
176
176
 
177
- const registryAddress = await deployL1Contract(
178
- walletClient,
179
- publicClient,
180
- contractsToDeploy.registry.contractAbi,
181
- contractsToDeploy.registry.contractBytecode,
182
- );
177
+ const registryAddress = await deployer.deploy(contractsToDeploy.registry, [account.address.toString()]);
183
178
  logger.info(`Deployed Registry at ${registryAddress}`);
184
179
 
185
- const availabilityOracleAddress = await deployL1Contract(
186
- walletClient,
187
- publicClient,
188
- contractsToDeploy.availabilityOracle.contractAbi,
189
- contractsToDeploy.availabilityOracle.contractBytecode,
190
- );
180
+ const availabilityOracleAddress = await deployer.deploy(contractsToDeploy.availabilityOracle);
191
181
  logger.info(`Deployed AvailabilityOracle at ${availabilityOracleAddress}`);
192
182
 
193
- const feeJuiceAddress = await deployL1Contract(
194
- walletClient,
195
- publicClient,
196
- contractsToDeploy.feeJuice.contractAbi,
197
- contractsToDeploy.feeJuice.contractBytecode,
198
- );
183
+ const feeJuiceAddress = await deployer.deploy(contractsToDeploy.feeJuice);
199
184
 
200
185
  logger.info(`Deployed Fee Juice at ${feeJuiceAddress}`);
201
186
 
202
- const rollupAddress = await deployL1Contract(
203
- walletClient,
204
- publicClient,
205
- contractsToDeploy.rollup.contractAbi,
206
- contractsToDeploy.rollup.contractBytecode,
207
- [
208
- getAddress(registryAddress.toString()),
209
- getAddress(availabilityOracleAddress.toString()),
210
- getAddress(feeJuiceAddress.toString()),
211
- args.vkTreeRoot.toString(),
212
- ],
187
+ const feeJuicePortalAddress = await deployer.deploy(contractsToDeploy.feeJuicePortal, [account.address.toString()]);
188
+
189
+ logger.info(`Deployed Gas Portal at ${feeJuicePortalAddress}`);
190
+
191
+ const feeJuicePortal = getContract({
192
+ address: feeJuicePortalAddress.toString(),
193
+ abi: contractsToDeploy.feeJuicePortal.contractAbi,
194
+ client: walletClient,
195
+ });
196
+
197
+ // fund the portal contract with Fee Juice
198
+ const feeJuice = getContract({
199
+ address: feeJuiceAddress.toString(),
200
+ abi: contractsToDeploy.feeJuice.contractAbi,
201
+ client: walletClient,
202
+ });
203
+
204
+ // @note This value MUST match what is in `constants.nr`. It is currently specified here instead of just importing
205
+ // because there is circular dependency hell. This is a temporary solution. #3342
206
+ const FEE_JUICE_INITIAL_MINT = 20000000000;
207
+ const receipt = await feeJuice.write.mint([feeJuicePortalAddress.toString(), FEE_JUICE_INITIAL_MINT], {} as any);
208
+ await publicClient.waitForTransactionReceipt({ hash: receipt });
209
+ logger.info(`Funded fee juice portal contract with Fee Juice`);
210
+
211
+ if ((await feeJuicePortal.read.registry([])) === zeroAddress) {
212
+ await publicClient.waitForTransactionReceipt({
213
+ hash: await feeJuicePortal.write.initialize([
214
+ registryAddress.toString(),
215
+ feeJuiceAddress.toString(),
216
+ args.l2FeeJuiceAddress.toString(),
217
+ ]),
218
+ });
219
+ logger.verbose(`Fee juice portal initialized with registry ${registryAddress.toString()}`);
220
+ } else {
221
+ logger.verbose(`Fee juice portal is already initialized`);
222
+ }
223
+
224
+ logger.info(
225
+ `Initialized Gas Portal at ${feeJuicePortalAddress} to bridge between L1 ${feeJuiceAddress} to L2 ${args.l2FeeJuiceAddress}`,
213
226
  );
227
+
228
+ const rollupAddress = await deployer.deploy(contractsToDeploy.rollup, [
229
+ getAddress(registryAddress.toString()),
230
+ getAddress(availabilityOracleAddress.toString()),
231
+ getAddress(feeJuicePortalAddress.toString()),
232
+ args.vkTreeRoot.toString(),
233
+ account.address.toString(),
234
+ ]);
214
235
  logger.info(`Deployed Rollup at ${rollupAddress}`);
215
236
 
216
237
  // Set initial blocks as proven if requested
@@ -253,48 +274,12 @@ export const deployL1Contracts = async (
253
274
  abi: contractsToDeploy.registry.contractAbi,
254
275
  client: walletClient,
255
276
  });
256
- await registryContract.write.upgrade(
257
- [getAddress(rollupAddress.toString()), getAddress(inboxAddress.toString()), getAddress(outboxAddress.toString())],
258
- { account },
259
- );
260
-
261
- // this contract remains uninitialized because at this point we don't know the address of the Fee Juice on L2
262
- const feeJuicePortalAddress = await deployL1Contract(
263
- walletClient,
264
- publicClient,
265
- contractsToDeploy.feeJuicePortal.contractAbi,
266
- contractsToDeploy.feeJuicePortal.contractBytecode,
267
- );
268
-
269
- logger.info(`Deployed Gas Portal at ${feeJuicePortalAddress}`);
270
-
271
- const feeJuicePortal = getContract({
272
- address: feeJuicePortalAddress.toString(),
273
- abi: contractsToDeploy.feeJuicePortal.contractAbi,
274
- client: walletClient,
275
- });
276
-
277
- await publicClient.waitForTransactionReceipt({
278
- hash: await feeJuicePortal.write.initialize([
279
- registryAddress.toString(),
280
- feeJuiceAddress.toString(),
281
- args.l2FeeJuiceAddress.toString(),
282
- ]),
283
- });
284
-
285
- logger.info(
286
- `Initialized Gas Portal at ${feeJuicePortalAddress} to bridge between L1 ${feeJuiceAddress} to L2 ${args.l2FeeJuiceAddress}`,
287
- );
288
-
289
- // fund the rollup contract with Fee Juice
290
- const feeJuice = getContract({
291
- address: feeJuiceAddress.toString(),
292
- abi: contractsToDeploy.feeJuice.contractAbi,
293
- client: walletClient,
294
- });
295
- const receipt = await feeJuice.write.mint([rollupAddress.toString(), 100000000000000000000n], {} as any);
296
- await publicClient.waitForTransactionReceipt({ hash: receipt });
297
- logger.info(`Funded rollup contract with Fee Juice`);
277
+ if (!(await registryContract.read.isRollupRegistered([getAddress(rollupAddress.toString())]))) {
278
+ await registryContract.write.upgrade([getAddress(rollupAddress.toString())], { account });
279
+ logger.verbose(`Upgraded registry contract at ${registryAddress} to rollup ${rollupAddress}`);
280
+ } else {
281
+ logger.verbose(`Registry ${registryAddress} has already registered rollup ${rollupAddress}`);
282
+ }
298
283
 
299
284
  const l1Contracts: L1ContractAddresses = {
300
285
  availabilityOracleAddress,
@@ -313,6 +298,33 @@ export const deployL1Contracts = async (
313
298
  };
314
299
  };
315
300
 
301
+ class L1Deployer {
302
+ private salt: Hex | undefined;
303
+ constructor(
304
+ private walletClient: WalletClient<HttpTransport, Chain, Account>,
305
+ private publicClient: PublicClient<HttpTransport, Chain>,
306
+ maybeSalt: number | undefined,
307
+ private logger: DebugLogger,
308
+ ) {
309
+ this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), { size: 32 }) : undefined;
310
+ }
311
+
312
+ deploy(
313
+ params: { contractAbi: Narrow<Abi | readonly unknown[]>; contractBytecode: Hex },
314
+ args: readonly unknown[] = [],
315
+ ): Promise<EthAddress> {
316
+ return deployL1Contract(
317
+ this.walletClient,
318
+ this.publicClient,
319
+ params.contractAbi,
320
+ params.contractBytecode,
321
+ args,
322
+ this.salt,
323
+ this.logger,
324
+ );
325
+ }
326
+ }
327
+
316
328
  // docs:start:deployL1Contract
317
329
  /**
318
330
  * Helper function to deploy ETH contracts.
@@ -329,23 +341,40 @@ export async function deployL1Contract(
329
341
  abi: Narrow<Abi | readonly unknown[]>,
330
342
  bytecode: Hex,
331
343
  args: readonly unknown[] = [],
344
+ maybeSalt?: Hex,
345
+ logger?: DebugLogger,
332
346
  ): Promise<EthAddress> {
333
- const hash = await walletClient.deployContract({
334
- abi,
335
- bytecode,
336
- args,
337
- });
338
-
339
- const receipt = await publicClient.waitForTransactionReceipt({ hash, pollingInterval: 100 });
340
- const contractAddress = receipt.contractAddress;
341
- if (!contractAddress) {
342
- throw new Error(
343
- `No contract address found in receipt: ${JSON.stringify(receipt, (_, val) =>
344
- typeof val === 'bigint' ? String(val) : val,
345
- )}`,
346
- );
347
+ if (maybeSalt) {
348
+ const salt = padHex(maybeSalt, { size: 32 });
349
+ const deployer: Hex = '0x4e59b44847b379578588920cA78FbF26c0B4956C';
350
+ const calldata = encodeDeployData({ abi, bytecode, args });
351
+ const address = getContractAddress({ from: deployer, salt, bytecode: calldata, opcode: 'CREATE2' });
352
+ const existing = await publicClient.getBytecode({ address });
353
+
354
+ if (existing === undefined || existing === '0x') {
355
+ const hash = await walletClient.sendTransaction({
356
+ to: deployer,
357
+ data: concatHex([salt, calldata]),
358
+ });
359
+ logger?.verbose(`Deploying contract with salt ${salt} to address ${address} in tx ${hash}`);
360
+ await publicClient.waitForTransactionReceipt({ hash, pollingInterval: 100 });
361
+ } else {
362
+ logger?.verbose(`Skipping existing deployment of contract with salt ${salt} to address ${address}`);
363
+ }
364
+ return EthAddress.fromString(address);
365
+ } else {
366
+ const hash = await walletClient.deployContract({ abi, bytecode, args });
367
+ logger?.verbose(`Deploying contract in tx ${hash}`);
368
+ const receipt = await publicClient.waitForTransactionReceipt({ hash, pollingInterval: 100 });
369
+ const contractAddress = receipt.contractAddress;
370
+ if (!contractAddress) {
371
+ throw new Error(
372
+ `No contract address found in receipt: ${JSON.stringify(receipt, (_, val) =>
373
+ typeof val === 'bigint' ? String(val) : val,
374
+ )}`,
375
+ );
376
+ }
377
+ return EthAddress.fromString(contractAddress);
347
378
  }
348
-
349
- return EthAddress.fromString(receipt.contractAddress!);
350
379
  }
351
380
  // docs:end:deployL1Contract