@aztec/ethereum 0.49.2 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -65,7 +65,7 @@ export interface L1ContractArtifactsForDeployment {
65
65
  */
66
66
  feeJuice: ContractArtifacts;
67
67
  /**
68
- * Gas portal contract artifacts. Optional for now as gas is not strictly enforced
68
+ * Fee juice portal contract artifacts. Optional for now as gas is not strictly enforced
69
69
  */
70
70
  feeJuicePortal: ContractArtifacts;
71
71
  }
@@ -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,CAsK3B,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
  /**
@@ -49,33 +49,63 @@ export const deployL1Contracts = async (rpcUrl, account, chain, logger, contract
49
49
  };
50
50
  return await (await fetch(rpcUrl, content)).json();
51
51
  };
52
- const interval = 12;
53
- const res = await rpcCall(rpcUrl, 'anvil_setBlockTimestampInterval', [interval]);
54
- if (res.error) {
55
- throw new Error(`Error setting block interval: ${res.error.message}`);
52
+ if (chain.id == foundry.id) {
53
+ const interval = 12;
54
+ const res = await rpcCall(rpcUrl, 'anvil_setBlockTimestampInterval', [interval]);
55
+ if (res.error) {
56
+ throw new Error(`Error setting block interval: ${res.error.message}`);
57
+ }
58
+ logger.info(`Set block interval to ${interval}`);
56
59
  }
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);
60
+ logger.info(`Deploying contracts from ${account.address.toString()}...`);
61
+ const walletClient = createWalletClient({ account, chain, transport: http(rpcUrl) });
62
+ const publicClient = createPublicClient({ chain, transport: http(rpcUrl) });
63
+ const deployer = new L1Deployer(walletClient, publicClient, args.salt, logger);
64
+ const registryAddress = await deployer.deploy(contractsToDeploy.registry, [account.address.toString()]);
69
65
  logger.info(`Deployed Registry at ${registryAddress}`);
70
- const availabilityOracleAddress = await deployL1Contract(walletClient, publicClient, contractsToDeploy.availabilityOracle.contractAbi, contractsToDeploy.availabilityOracle.contractBytecode);
66
+ const availabilityOracleAddress = await deployer.deploy(contractsToDeploy.availabilityOracle);
71
67
  logger.info(`Deployed AvailabilityOracle at ${availabilityOracleAddress}`);
72
- const feeJuiceAddress = await deployL1Contract(walletClient, publicClient, contractsToDeploy.feeJuice.contractAbi, contractsToDeploy.feeJuice.contractBytecode);
68
+ const feeJuiceAddress = await deployer.deploy(contractsToDeploy.feeJuice);
73
69
  logger.info(`Deployed Fee Juice at ${feeJuiceAddress}`);
74
- const rollupAddress = await deployL1Contract(walletClient, publicClient, contractsToDeploy.rollup.contractAbi, contractsToDeploy.rollup.contractBytecode, [
70
+ const feeJuicePortalAddress = await deployer.deploy(contractsToDeploy.feeJuicePortal, [account.address.toString()]);
71
+ logger.info(`Deployed Gas Portal at ${feeJuicePortalAddress}`);
72
+ const feeJuicePortal = getContract({
73
+ address: feeJuicePortalAddress.toString(),
74
+ abi: contractsToDeploy.feeJuicePortal.contractAbi,
75
+ client: walletClient,
76
+ });
77
+ // fund the portal contract with Fee Juice
78
+ const feeJuice = getContract({
79
+ address: feeJuiceAddress.toString(),
80
+ abi: contractsToDeploy.feeJuice.contractAbi,
81
+ client: walletClient,
82
+ });
83
+ // @note This value MUST match what is in `constants.nr`. It is currently specified here instead of just importing
84
+ // because there is circular dependency hell. This is a temporary solution. #3342
85
+ const FEE_JUICE_INITIAL_MINT = 20000000000;
86
+ const receipt = await feeJuice.write.mint([feeJuicePortalAddress.toString(), FEE_JUICE_INITIAL_MINT], {});
87
+ await publicClient.waitForTransactionReceipt({ hash: receipt });
88
+ logger.info(`Funded fee juice portal contract with Fee Juice`);
89
+ if ((await feeJuicePortal.read.registry([])) === zeroAddress) {
90
+ await publicClient.waitForTransactionReceipt({
91
+ hash: await feeJuicePortal.write.initialize([
92
+ registryAddress.toString(),
93
+ feeJuiceAddress.toString(),
94
+ args.l2FeeJuiceAddress.toString(),
95
+ ]),
96
+ });
97
+ logger.verbose(`Fee juice portal initialized with registry ${registryAddress.toString()}`);
98
+ }
99
+ else {
100
+ logger.verbose(`Fee juice portal is already initialized`);
101
+ }
102
+ logger.info(`Initialized Gas Portal at ${feeJuicePortalAddress} to bridge between L1 ${feeJuiceAddress} to L2 ${args.l2FeeJuiceAddress}`);
103
+ const rollupAddress = await deployer.deploy(contractsToDeploy.rollup, [
75
104
  getAddress(registryAddress.toString()),
76
105
  getAddress(availabilityOracleAddress.toString()),
77
- getAddress(feeJuiceAddress.toString()),
106
+ getAddress(feeJuicePortalAddress.toString()),
78
107
  args.vkTreeRoot.toString(),
108
+ account.address.toString(),
79
109
  ]);
80
110
  logger.info(`Deployed Rollup at ${rollupAddress}`);
81
111
  // Set initial blocks as proven if requested
@@ -115,32 +145,13 @@ export const deployL1Contracts = async (rpcUrl, account, chain, logger, contract
115
145
  abi: contractsToDeploy.registry.contractAbi,
116
146
  client: walletClient,
117
147
  });
118
- await registryContract.write.upgrade([getAddress(rollupAddress.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`);
148
+ if (!(await registryContract.read.isRollupRegistered([getAddress(rollupAddress.toString())]))) {
149
+ await registryContract.write.upgrade([getAddress(rollupAddress.toString())], { account });
150
+ logger.verbose(`Upgraded registry contract at ${registryAddress} to rollup ${rollupAddress}`);
151
+ }
152
+ else {
153
+ logger.verbose(`Registry ${registryAddress} has already registered rollup ${rollupAddress}`);
154
+ }
144
155
  const l1Contracts = {
145
156
  availabilityOracleAddress,
146
157
  rollupAddress,
@@ -156,6 +167,17 @@ export const deployL1Contracts = async (rpcUrl, account, chain, logger, contract
156
167
  l1ContractAddresses: l1Contracts,
157
168
  };
158
169
  };
170
+ class L1Deployer {
171
+ constructor(walletClient, publicClient, maybeSalt, logger) {
172
+ this.walletClient = walletClient;
173
+ this.publicClient = publicClient;
174
+ this.logger = logger;
175
+ this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), { size: 32 }) : undefined;
176
+ }
177
+ deploy(params, args = []) {
178
+ return deployL1Contract(this.walletClient, this.publicClient, params.contractAbi, params.contractBytecode, args, this.salt, this.logger);
179
+ }
180
+ }
159
181
  // docs:start:deployL1Contract
160
182
  /**
161
183
  * Helper function to deploy ETH contracts.
@@ -166,18 +188,36 @@ export const deployL1Contracts = async (rpcUrl, account, chain, logger, contract
166
188
  * @param args - Constructor arguments for the contract.
167
189
  * @returns The ETH address the contract was deployed to.
168
190
  */
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)}`);
191
+ export async function deployL1Contract(walletClient, publicClient, abi, bytecode, args = [], maybeSalt, logger) {
192
+ if (maybeSalt) {
193
+ const salt = padHex(maybeSalt, { size: 32 });
194
+ const deployer = '0x4e59b44847b379578588920cA78FbF26c0B4956C';
195
+ const calldata = encodeDeployData({ abi, bytecode, args });
196
+ const address = getContractAddress({ from: deployer, salt, bytecode: calldata, opcode: 'CREATE2' });
197
+ const existing = await publicClient.getBytecode({ address });
198
+ if (existing === undefined || existing === '0x') {
199
+ const hash = await walletClient.sendTransaction({
200
+ to: deployer,
201
+ data: concatHex([salt, calldata]),
202
+ });
203
+ logger?.verbose(`Deploying contract with salt ${salt} to address ${address} in tx ${hash}`);
204
+ await publicClient.waitForTransactionReceipt({ hash, pollingInterval: 100 });
205
+ }
206
+ else {
207
+ logger?.verbose(`Skipping existing deployment of contract with salt ${salt} to address ${address}`);
208
+ }
209
+ return EthAddress.fromString(address);
210
+ }
211
+ else {
212
+ const hash = await walletClient.deployContract({ abi, bytecode, args });
213
+ logger?.verbose(`Deploying contract in tx ${hash}`);
214
+ const receipt = await publicClient.waitForTransactionReceipt({ hash, pollingInterval: 100 });
215
+ const contractAddress = receipt.contractAddress;
216
+ if (!contractAddress) {
217
+ throw new Error(`No contract address found in receipt: ${JSON.stringify(receipt, (_, val) => typeof val === 'bigint' ? String(val) : val)}`);
218
+ }
219
+ return EthAddress.fromString(contractAddress);
179
220
  }
180
- return EthAddress.fromString(receipt.contractAddress);
181
221
  }
182
222
  // docs:end:deployL1Contract
183
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95X2wxX2NvbnRyYWN0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9kZXBsb3lfbDFfY29udHJhY3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUszRCxPQUFPLEVBT0wsa0JBQWtCLEVBQ2xCLGtCQUFrQixFQUNsQixVQUFVLEVBQ1YsV0FBVyxFQUNYLElBQUksR0FDTCxNQUFNLE1BQU0sQ0FBQztBQUNkLE9BQU8sRUFBMEMsaUJBQWlCLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDL0csT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQTJFdEM7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FDN0IsTUFBYyxFQUNkLCtCQUF1RixFQUN2RixRQUFlLE9BQU87SUFFdEIsTUFBTSxTQUFTLEdBQ2IsT0FBTywrQkFBK0IsS0FBSyxRQUFRO1FBQ2pELENBQUMsQ0FBQywrQkFBK0IsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDO1lBQ2hELENBQUMsQ0FBQyxtQkFBbUIsQ0FBQywrQkFBZ0QsQ0FBQztZQUN2RSxDQUFDLENBQUMsaUJBQWlCLENBQUMsK0JBQStCLENBQUM7UUFDdEQsQ0FBQyxDQUFDLCtCQUErQixDQUFDO0lBRXRDLE1BQU0sWUFBWSxHQUFHLGtCQUFrQixDQUFDO1FBQ3RDLE9BQU8sRUFBRSxTQUFTO1FBQ2xCLEtBQUs7UUFDTCxTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQztLQUN4QixDQUFDLENBQUM7SUFDSCxNQUFNLFlBQVksR0FBRyxrQkFBa0IsQ0FBQztRQUN0QyxLQUFLO1FBQ0wsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUM7S0FDeEIsQ0FBQyxDQUFDO0lBRUgsT0FBTyxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsQ0FBQztBQUN4QyxDQUFDO0FBRUQ7Ozs7Ozs7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
223
+ //# 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.49.2",
3
+ "version": "0.51.0",
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.49.2",
27
+ "@aztec/foundation": "0.51.0",
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';
@@ -83,7 +89,7 @@ export interface L1ContractArtifactsForDeployment {
83
89
  */
84
90
  feeJuice: ContractArtifacts;
85
91
  /**
86
- * Gas portal contract artifacts. Optional for now as gas is not strictly enforced
92
+ * Fee juice portal contract artifacts. Optional for now as gas is not strictly enforced
87
93
  */
88
94
  feeJuicePortal: ContractArtifacts;
89
95
  }
@@ -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
@@ -155,62 +161,79 @@ export const deployL1Contracts = async (
155
161
  };
156
162
  return await (await fetch(rpcUrl, content)).json();
157
163
  };
158
- const interval = 12;
159
- const res = await rpcCall(rpcUrl, 'anvil_setBlockTimestampInterval', [interval]);
160
- if (res.error) {
161
- throw new Error(`Error setting block interval: ${res.error.message}`);
164
+ if (chain.id == foundry.id) {
165
+ const interval = 12;
166
+ const res = await rpcCall(rpcUrl, 'anvil_setBlockTimestampInterval', [interval]);
167
+ if (res.error) {
168
+ throw new Error(`Error setting block interval: ${res.error.message}`);
169
+ }
170
+ logger.info(`Set block interval to ${interval}`);
162
171
  }
163
- logger.info(`Set block interval to ${interval}`);
164
172
 
165
- logger.debug('Deploying contracts...');
173
+ logger.info(`Deploying contracts from ${account.address.toString()}...`);
166
174
 
167
- const walletClient = createWalletClient({
168
- account,
169
- chain,
170
- transport: http(rpcUrl),
171
- });
172
- const publicClient = createPublicClient({
173
- chain,
174
- transport: http(rpcUrl),
175
- });
175
+ const walletClient = createWalletClient({ account, chain, transport: http(rpcUrl) });
176
+ const publicClient = createPublicClient({ chain, transport: http(rpcUrl) });
177
+ const deployer = new L1Deployer(walletClient, publicClient, args.salt, logger);
176
178
 
177
- const registryAddress = await deployL1Contract(
178
- walletClient,
179
- publicClient,
180
- contractsToDeploy.registry.contractAbi,
181
- contractsToDeploy.registry.contractBytecode,
182
- );
179
+ const registryAddress = await deployer.deploy(contractsToDeploy.registry, [account.address.toString()]);
183
180
  logger.info(`Deployed Registry at ${registryAddress}`);
184
181
 
185
- const availabilityOracleAddress = await deployL1Contract(
186
- walletClient,
187
- publicClient,
188
- contractsToDeploy.availabilityOracle.contractAbi,
189
- contractsToDeploy.availabilityOracle.contractBytecode,
190
- );
182
+ const availabilityOracleAddress = await deployer.deploy(contractsToDeploy.availabilityOracle);
191
183
  logger.info(`Deployed AvailabilityOracle at ${availabilityOracleAddress}`);
192
184
 
193
- const feeJuiceAddress = await deployL1Contract(
194
- walletClient,
195
- publicClient,
196
- contractsToDeploy.feeJuice.contractAbi,
197
- contractsToDeploy.feeJuice.contractBytecode,
198
- );
185
+ const feeJuiceAddress = await deployer.deploy(contractsToDeploy.feeJuice);
199
186
 
200
187
  logger.info(`Deployed Fee Juice at ${feeJuiceAddress}`);
201
188
 
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
- ],
189
+ const feeJuicePortalAddress = await deployer.deploy(contractsToDeploy.feeJuicePortal, [account.address.toString()]);
190
+
191
+ logger.info(`Deployed Gas Portal at ${feeJuicePortalAddress}`);
192
+
193
+ const feeJuicePortal = getContract({
194
+ address: feeJuicePortalAddress.toString(),
195
+ abi: contractsToDeploy.feeJuicePortal.contractAbi,
196
+ client: walletClient,
197
+ });
198
+
199
+ // fund the portal contract with Fee Juice
200
+ const feeJuice = getContract({
201
+ address: feeJuiceAddress.toString(),
202
+ abi: contractsToDeploy.feeJuice.contractAbi,
203
+ client: walletClient,
204
+ });
205
+
206
+ // @note This value MUST match what is in `constants.nr`. It is currently specified here instead of just importing
207
+ // because there is circular dependency hell. This is a temporary solution. #3342
208
+ const FEE_JUICE_INITIAL_MINT = 20000000000;
209
+ const receipt = await feeJuice.write.mint([feeJuicePortalAddress.toString(), FEE_JUICE_INITIAL_MINT], {} as any);
210
+ await publicClient.waitForTransactionReceipt({ hash: receipt });
211
+ logger.info(`Funded fee juice portal contract with Fee Juice`);
212
+
213
+ if ((await feeJuicePortal.read.registry([])) === zeroAddress) {
214
+ await publicClient.waitForTransactionReceipt({
215
+ hash: await feeJuicePortal.write.initialize([
216
+ registryAddress.toString(),
217
+ feeJuiceAddress.toString(),
218
+ args.l2FeeJuiceAddress.toString(),
219
+ ]),
220
+ });
221
+ logger.verbose(`Fee juice portal initialized with registry ${registryAddress.toString()}`);
222
+ } else {
223
+ logger.verbose(`Fee juice portal is already initialized`);
224
+ }
225
+
226
+ logger.info(
227
+ `Initialized Gas Portal at ${feeJuicePortalAddress} to bridge between L1 ${feeJuiceAddress} to L2 ${args.l2FeeJuiceAddress}`,
213
228
  );
229
+
230
+ const rollupAddress = await deployer.deploy(contractsToDeploy.rollup, [
231
+ getAddress(registryAddress.toString()),
232
+ getAddress(availabilityOracleAddress.toString()),
233
+ getAddress(feeJuicePortalAddress.toString()),
234
+ args.vkTreeRoot.toString(),
235
+ account.address.toString(),
236
+ ]);
214
237
  logger.info(`Deployed Rollup at ${rollupAddress}`);
215
238
 
216
239
  // Set initial blocks as proven if requested
@@ -253,45 +276,12 @@ export const deployL1Contracts = async (
253
276
  abi: contractsToDeploy.registry.contractAbi,
254
277
  client: walletClient,
255
278
  });
256
- await registryContract.write.upgrade([getAddress(rollupAddress.toString())], { account });
257
-
258
- // this contract remains uninitialized because at this point we don't know the address of the Fee Juice on L2
259
- const feeJuicePortalAddress = await deployL1Contract(
260
- walletClient,
261
- publicClient,
262
- contractsToDeploy.feeJuicePortal.contractAbi,
263
- contractsToDeploy.feeJuicePortal.contractBytecode,
264
- );
265
-
266
- logger.info(`Deployed Gas Portal at ${feeJuicePortalAddress}`);
267
-
268
- const feeJuicePortal = getContract({
269
- address: feeJuicePortalAddress.toString(),
270
- abi: contractsToDeploy.feeJuicePortal.contractAbi,
271
- client: walletClient,
272
- });
273
-
274
- await publicClient.waitForTransactionReceipt({
275
- hash: await feeJuicePortal.write.initialize([
276
- registryAddress.toString(),
277
- feeJuiceAddress.toString(),
278
- args.l2FeeJuiceAddress.toString(),
279
- ]),
280
- });
281
-
282
- logger.info(
283
- `Initialized Gas Portal at ${feeJuicePortalAddress} to bridge between L1 ${feeJuiceAddress} to L2 ${args.l2FeeJuiceAddress}`,
284
- );
285
-
286
- // fund the rollup contract with Fee Juice
287
- const feeJuice = getContract({
288
- address: feeJuiceAddress.toString(),
289
- abi: contractsToDeploy.feeJuice.contractAbi,
290
- client: walletClient,
291
- });
292
- const receipt = await feeJuice.write.mint([rollupAddress.toString(), 100000000000000000000n], {} as any);
293
- await publicClient.waitForTransactionReceipt({ hash: receipt });
294
- logger.info(`Funded rollup contract with Fee Juice`);
279
+ if (!(await registryContract.read.isRollupRegistered([getAddress(rollupAddress.toString())]))) {
280
+ await registryContract.write.upgrade([getAddress(rollupAddress.toString())], { account });
281
+ logger.verbose(`Upgraded registry contract at ${registryAddress} to rollup ${rollupAddress}`);
282
+ } else {
283
+ logger.verbose(`Registry ${registryAddress} has already registered rollup ${rollupAddress}`);
284
+ }
295
285
 
296
286
  const l1Contracts: L1ContractAddresses = {
297
287
  availabilityOracleAddress,
@@ -310,6 +300,33 @@ export const deployL1Contracts = async (
310
300
  };
311
301
  };
312
302
 
303
+ class L1Deployer {
304
+ private salt: Hex | undefined;
305
+ constructor(
306
+ private walletClient: WalletClient<HttpTransport, Chain, Account>,
307
+ private publicClient: PublicClient<HttpTransport, Chain>,
308
+ maybeSalt: number | undefined,
309
+ private logger: DebugLogger,
310
+ ) {
311
+ this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), { size: 32 }) : undefined;
312
+ }
313
+
314
+ deploy(
315
+ params: { contractAbi: Narrow<Abi | readonly unknown[]>; contractBytecode: Hex },
316
+ args: readonly unknown[] = [],
317
+ ): Promise<EthAddress> {
318
+ return deployL1Contract(
319
+ this.walletClient,
320
+ this.publicClient,
321
+ params.contractAbi,
322
+ params.contractBytecode,
323
+ args,
324
+ this.salt,
325
+ this.logger,
326
+ );
327
+ }
328
+ }
329
+
313
330
  // docs:start:deployL1Contract
314
331
  /**
315
332
  * Helper function to deploy ETH contracts.
@@ -326,23 +343,40 @@ export async function deployL1Contract(
326
343
  abi: Narrow<Abi | readonly unknown[]>,
327
344
  bytecode: Hex,
328
345
  args: readonly unknown[] = [],
346
+ maybeSalt?: Hex,
347
+ logger?: DebugLogger,
329
348
  ): Promise<EthAddress> {
330
- const hash = await walletClient.deployContract({
331
- abi,
332
- bytecode,
333
- args,
334
- });
335
-
336
- const receipt = await publicClient.waitForTransactionReceipt({ hash, pollingInterval: 100 });
337
- const contractAddress = receipt.contractAddress;
338
- if (!contractAddress) {
339
- throw new Error(
340
- `No contract address found in receipt: ${JSON.stringify(receipt, (_, val) =>
341
- typeof val === 'bigint' ? String(val) : val,
342
- )}`,
343
- );
349
+ if (maybeSalt) {
350
+ const salt = padHex(maybeSalt, { size: 32 });
351
+ const deployer: Hex = '0x4e59b44847b379578588920cA78FbF26c0B4956C';
352
+ const calldata = encodeDeployData({ abi, bytecode, args });
353
+ const address = getContractAddress({ from: deployer, salt, bytecode: calldata, opcode: 'CREATE2' });
354
+ const existing = await publicClient.getBytecode({ address });
355
+
356
+ if (existing === undefined || existing === '0x') {
357
+ const hash = await walletClient.sendTransaction({
358
+ to: deployer,
359
+ data: concatHex([salt, calldata]),
360
+ });
361
+ logger?.verbose(`Deploying contract with salt ${salt} to address ${address} in tx ${hash}`);
362
+ await publicClient.waitForTransactionReceipt({ hash, pollingInterval: 100 });
363
+ } else {
364
+ logger?.verbose(`Skipping existing deployment of contract with salt ${salt} to address ${address}`);
365
+ }
366
+ return EthAddress.fromString(address);
367
+ } else {
368
+ const hash = await walletClient.deployContract({ abi, bytecode, args });
369
+ logger?.verbose(`Deploying contract in tx ${hash}`);
370
+ const receipt = await publicClient.waitForTransactionReceipt({ hash, pollingInterval: 100 });
371
+ const contractAddress = receipt.contractAddress;
372
+ if (!contractAddress) {
373
+ throw new Error(
374
+ `No contract address found in receipt: ${JSON.stringify(receipt, (_, val) =>
375
+ typeof val === 'bigint' ? String(val) : val,
376
+ )}`,
377
+ );
378
+ }
379
+ return EthAddress.fromString(contractAddress);
344
380
  }
345
-
346
- return EthAddress.fromString(receipt.contractAddress!);
347
381
  }
348
382
  // docs:end:deployL1Contract