@aztec/ethereum 0.0.0-test.1 → 0.0.1-commit.017a351

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.
Files changed (285) hide show
  1. package/dest/account.d.ts +2 -0
  2. package/dest/account.d.ts.map +1 -0
  3. package/dest/account.js +4 -0
  4. package/dest/chain.d.ts +1 -1
  5. package/dest/client.d.ts +28 -4
  6. package/dest/client.d.ts.map +1 -1
  7. package/dest/client.js +73 -3
  8. package/dest/config.d.ts +70 -23
  9. package/dest/config.d.ts.map +1 -1
  10. package/dest/config.js +151 -34
  11. package/dest/constants.d.ts +1 -1
  12. package/dest/contracts/chain_state_override.d.ts +78 -0
  13. package/dest/contracts/chain_state_override.d.ts.map +1 -0
  14. package/dest/contracts/chain_state_override.js +137 -0
  15. package/dest/contracts/empire_base.d.ts +25 -8
  16. package/dest/contracts/empire_base.d.ts.map +1 -1
  17. package/dest/contracts/empire_base.js +75 -2
  18. package/dest/contracts/errors.d.ts +7 -0
  19. package/dest/contracts/errors.d.ts.map +1 -0
  20. package/dest/contracts/errors.js +12 -0
  21. package/dest/contracts/fee_asset_handler.d.ts +20 -0
  22. package/dest/contracts/fee_asset_handler.d.ts.map +1 -0
  23. package/dest/contracts/fee_asset_handler.js +59 -0
  24. package/dest/contracts/fee_asset_price_oracle.d.ts +105 -0
  25. package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
  26. package/dest/contracts/fee_asset_price_oracle.js +656 -0
  27. package/dest/contracts/fee_juice.d.ts +6 -7
  28. package/dest/contracts/fee_juice.d.ts.map +1 -1
  29. package/dest/contracts/fee_juice.js +27 -20
  30. package/dest/contracts/governance.d.ts +131 -43
  31. package/dest/contracts/governance.d.ts.map +1 -1
  32. package/dest/contracts/governance.js +281 -87
  33. package/dest/contracts/governance_proposer.d.ts +49 -13
  34. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  35. package/dest/contracts/governance_proposer.js +483 -26
  36. package/dest/contracts/gse.d.ts +32 -0
  37. package/dest/contracts/gse.d.ts.map +1 -0
  38. package/dest/contracts/gse.js +72 -0
  39. package/dest/contracts/inbox.d.ts +47 -0
  40. package/dest/contracts/inbox.d.ts.map +1 -0
  41. package/dest/contracts/inbox.js +85 -0
  42. package/dest/contracts/index.d.ts +11 -2
  43. package/dest/contracts/index.d.ts.map +1 -1
  44. package/dest/contracts/index.js +10 -1
  45. package/dest/contracts/log.d.ts +13 -0
  46. package/dest/contracts/log.d.ts.map +1 -0
  47. package/dest/contracts/log.js +1 -0
  48. package/dest/contracts/multicall.d.ts +136 -0
  49. package/dest/contracts/multicall.d.ts.map +1 -0
  50. package/dest/contracts/multicall.js +264 -0
  51. package/dest/contracts/outbox.d.ts +64 -0
  52. package/dest/contracts/outbox.d.ts.map +1 -0
  53. package/dest/contracts/outbox.js +113 -0
  54. package/dest/contracts/registry.d.ts +12 -5
  55. package/dest/contracts/registry.d.ts.map +1 -1
  56. package/dest/contracts/registry.js +74 -17
  57. package/dest/contracts/rollup.d.ts +5526 -52
  58. package/dest/contracts/rollup.d.ts.map +1 -1
  59. package/dest/contracts/rollup.js +1446 -118
  60. package/dest/contracts/slasher_contract.d.ts +44 -0
  61. package/dest/contracts/slasher_contract.d.ts.map +1 -0
  62. package/dest/contracts/slasher_contract.js +75 -0
  63. package/dest/contracts/slashing_proposer.d.ts +133 -15
  64. package/dest/contracts/slashing_proposer.d.ts.map +1 -1
  65. package/dest/contracts/slashing_proposer.js +293 -22
  66. package/dest/contracts/utils.d.ts +3 -0
  67. package/dest/contracts/utils.d.ts.map +1 -0
  68. package/dest/contracts/utils.js +11 -0
  69. package/dest/deploy_aztec_l1_contracts.d.ts +256 -0
  70. package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
  71. package/dest/deploy_aztec_l1_contracts.js +411 -0
  72. package/dest/deploy_l1_contract.d.ts +68 -0
  73. package/dest/deploy_l1_contract.d.ts.map +1 -0
  74. package/dest/deploy_l1_contract.js +312 -0
  75. package/dest/eth-signer/eth-signer.d.ts +21 -0
  76. package/dest/eth-signer/eth-signer.d.ts.map +1 -0
  77. package/dest/eth-signer/eth-signer.js +5 -0
  78. package/dest/eth-signer/index.d.ts +2 -0
  79. package/dest/eth-signer/index.d.ts.map +1 -0
  80. package/dest/eth-signer/index.js +1 -0
  81. package/dest/forwarder_proxy.d.ts +32 -0
  82. package/dest/forwarder_proxy.d.ts.map +1 -0
  83. package/dest/forwarder_proxy.js +93 -0
  84. package/dest/generated/l1-contracts-defaults.d.ts +30 -0
  85. package/dest/generated/l1-contracts-defaults.d.ts.map +1 -0
  86. package/dest/generated/l1-contracts-defaults.js +30 -0
  87. package/dest/l1_artifacts.d.ts +79270 -0
  88. package/dest/l1_artifacts.d.ts.map +1 -0
  89. package/dest/l1_artifacts.js +151 -0
  90. package/dest/l1_contract_addresses.d.ts +61 -45
  91. package/dest/l1_contract_addresses.d.ts.map +1 -1
  92. package/dest/l1_contract_addresses.js +99 -76
  93. package/dest/l1_reader.d.ts +8 -6
  94. package/dest/l1_reader.d.ts.map +1 -1
  95. package/dest/l1_reader.js +20 -12
  96. package/dest/l1_tx_utils/config.d.ts +65 -0
  97. package/dest/l1_tx_utils/config.d.ts.map +1 -0
  98. package/dest/l1_tx_utils/config.js +109 -0
  99. package/dest/l1_tx_utils/constants.d.ts +12 -0
  100. package/dest/l1_tx_utils/constants.d.ts.map +1 -0
  101. package/dest/l1_tx_utils/constants.js +39 -0
  102. package/dest/l1_tx_utils/factory.d.ts +32 -0
  103. package/dest/l1_tx_utils/factory.d.ts.map +1 -0
  104. package/dest/l1_tx_utils/factory.js +22 -0
  105. package/dest/l1_tx_utils/fee-strategies/index.d.ts +10 -0
  106. package/dest/l1_tx_utils/fee-strategies/index.d.ts.map +1 -0
  107. package/dest/l1_tx_utils/fee-strategies/index.js +12 -0
  108. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts +8 -0
  109. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts.map +1 -0
  110. package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +129 -0
  111. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts +23 -0
  112. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts.map +1 -0
  113. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +191 -0
  114. package/dest/l1_tx_utils/fee-strategies/types.d.ts +51 -0
  115. package/dest/l1_tx_utils/fee-strategies/types.d.ts.map +1 -0
  116. package/dest/l1_tx_utils/fee-strategies/types.js +3 -0
  117. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +41 -0
  118. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -0
  119. package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +42 -0
  120. package/dest/l1_tx_utils/index-blobs.d.ts +3 -0
  121. package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -0
  122. package/dest/l1_tx_utils/index-blobs.js +2 -0
  123. package/dest/l1_tx_utils/index.d.ts +13 -0
  124. package/dest/l1_tx_utils/index.d.ts.map +1 -0
  125. package/dest/l1_tx_utils/index.js +13 -0
  126. package/dest/l1_tx_utils/interfaces.d.ts +76 -0
  127. package/dest/l1_tx_utils/interfaces.d.ts.map +1 -0
  128. package/dest/l1_tx_utils/interfaces.js +4 -0
  129. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +233 -0
  130. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -0
  131. package/dest/l1_tx_utils/l1_fee_analyzer.js +506 -0
  132. package/dest/l1_tx_utils/l1_tx_utils.d.ts +113 -0
  133. package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -0
  134. package/dest/l1_tx_utils/l1_tx_utils.js +658 -0
  135. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +83 -0
  136. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -0
  137. package/dest/l1_tx_utils/readonly_l1_tx_utils.js +328 -0
  138. package/dest/l1_tx_utils/signer.d.ts +4 -0
  139. package/dest/l1_tx_utils/signer.d.ts.map +1 -0
  140. package/dest/l1_tx_utils/signer.js +16 -0
  141. package/dest/l1_tx_utils/tx_delayer.d.ts +58 -0
  142. package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
  143. package/dest/l1_tx_utils/tx_delayer.js +223 -0
  144. package/dest/l1_tx_utils/types.d.ts +67 -0
  145. package/dest/l1_tx_utils/types.d.ts.map +1 -0
  146. package/dest/l1_tx_utils/types.js +26 -0
  147. package/dest/l1_tx_utils/utils.d.ts +4 -0
  148. package/dest/l1_tx_utils/utils.d.ts.map +1 -0
  149. package/dest/l1_tx_utils/utils.js +14 -0
  150. package/dest/l1_types.d.ts +6 -0
  151. package/dest/l1_types.d.ts.map +1 -0
  152. package/dest/l1_types.js +1 -0
  153. package/dest/publisher_manager.d.ts +30 -0
  154. package/dest/publisher_manager.d.ts.map +1 -0
  155. package/dest/publisher_manager.js +162 -0
  156. package/dest/queries.d.ts +17 -4
  157. package/dest/queries.d.ts.map +1 -1
  158. package/dest/queries.js +120 -12
  159. package/dest/test/chain_monitor.d.ts +95 -0
  160. package/dest/test/chain_monitor.d.ts.map +1 -0
  161. package/dest/test/chain_monitor.js +249 -0
  162. package/dest/test/eth_cheat_codes.d.ts +237 -0
  163. package/dest/test/eth_cheat_codes.d.ts.map +1 -0
  164. package/dest/test/eth_cheat_codes.js +573 -0
  165. package/dest/test/eth_cheat_codes_with_state.d.ts +2 -2
  166. package/dest/test/eth_cheat_codes_with_state.d.ts.map +1 -1
  167. package/dest/test/eth_cheat_codes_with_state.js +1 -1
  168. package/dest/test/index.d.ts +4 -3
  169. package/dest/test/index.d.ts.map +1 -1
  170. package/dest/test/index.js +3 -2
  171. package/dest/test/rollup_cheat_codes.d.ts +118 -0
  172. package/dest/test/rollup_cheat_codes.d.ts.map +1 -0
  173. package/dest/test/rollup_cheat_codes.js +344 -0
  174. package/dest/test/start_anvil.d.ts +30 -2
  175. package/dest/test/start_anvil.d.ts.map +1 -1
  176. package/dest/test/start_anvil.js +147 -24
  177. package/dest/test/upgrade_utils.d.ts +6 -5
  178. package/dest/test/upgrade_utils.d.ts.map +1 -1
  179. package/dest/test/upgrade_utils.js +23 -16
  180. package/dest/types.d.ts +62 -8
  181. package/dest/types.d.ts.map +1 -1
  182. package/dest/types.js +3 -1
  183. package/dest/utils.d.ts +25 -4
  184. package/dest/utils.d.ts.map +1 -1
  185. package/dest/utils.js +142 -91
  186. package/dest/zkPassportVerifierAddress.d.ts +15 -0
  187. package/dest/zkPassportVerifierAddress.d.ts.map +1 -0
  188. package/dest/zkPassportVerifierAddress.js +11 -0
  189. package/package.json +52 -26
  190. package/src/account.ts +5 -0
  191. package/src/client.ts +107 -5
  192. package/src/config.ts +218 -43
  193. package/src/contracts/README.md +157 -0
  194. package/src/contracts/chain_state_override.ts +200 -0
  195. package/src/contracts/empire_base.ts +77 -7
  196. package/src/contracts/errors.ts +13 -0
  197. package/src/contracts/fee_asset_handler.ts +66 -0
  198. package/src/contracts/fee_asset_price_oracle.ts +285 -0
  199. package/src/contracts/fee_juice.ts +29 -15
  200. package/src/contracts/governance.ts +343 -74
  201. package/src/contracts/governance_proposer.ts +128 -25
  202. package/src/contracts/gse.ts +88 -0
  203. package/src/contracts/inbox.ts +123 -0
  204. package/src/contracts/index.ts +10 -1
  205. package/src/contracts/log.ts +13 -0
  206. package/src/contracts/multicall.ts +296 -0
  207. package/src/contracts/outbox.ts +132 -0
  208. package/src/contracts/registry.ts +81 -26
  209. package/src/contracts/rollup.ts +1246 -90
  210. package/src/contracts/slasher_contract.ts +89 -0
  211. package/src/contracts/slashing_proposer.ts +296 -27
  212. package/src/contracts/utils.ts +14 -0
  213. package/src/deploy_aztec_l1_contracts.ts +646 -0
  214. package/src/deploy_l1_contract.ts +362 -0
  215. package/src/eth-signer/eth-signer.ts +25 -0
  216. package/src/eth-signer/index.ts +1 -0
  217. package/src/forwarder_proxy.ts +108 -0
  218. package/src/generated/l1-contracts-defaults.ts +32 -0
  219. package/src/l1_artifacts.ts +231 -0
  220. package/src/l1_contract_addresses.ts +121 -80
  221. package/src/l1_reader.ts +31 -16
  222. package/src/l1_tx_utils/README.md +177 -0
  223. package/src/l1_tx_utils/config.ts +181 -0
  224. package/src/l1_tx_utils/constants.ts +29 -0
  225. package/src/l1_tx_utils/factory.ts +64 -0
  226. package/src/l1_tx_utils/fee-strategies/index.ts +22 -0
  227. package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +163 -0
  228. package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +245 -0
  229. package/src/l1_tx_utils/fee-strategies/types.ts +56 -0
  230. package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +108 -0
  231. package/src/l1_tx_utils/index-blobs.ts +2 -0
  232. package/src/l1_tx_utils/index.ts +15 -0
  233. package/src/l1_tx_utils/interfaces.ts +86 -0
  234. package/src/l1_tx_utils/l1_fee_analyzer.ts +803 -0
  235. package/src/l1_tx_utils/l1_tx_utils.ts +789 -0
  236. package/src/l1_tx_utils/readonly_l1_tx_utils.ts +424 -0
  237. package/src/l1_tx_utils/signer.ts +28 -0
  238. package/src/l1_tx_utils/tx_delayer.ts +303 -0
  239. package/src/l1_tx_utils/types.ts +85 -0
  240. package/src/l1_tx_utils/utils.ts +16 -0
  241. package/src/l1_types.ts +6 -0
  242. package/src/publisher_manager.ts +203 -0
  243. package/src/queries.ts +149 -17
  244. package/src/test/chain_monitor.ts +307 -0
  245. package/src/test/eth_cheat_codes.ts +600 -0
  246. package/src/test/eth_cheat_codes_with_state.ts +1 -1
  247. package/src/test/index.ts +3 -2
  248. package/src/test/rollup_cheat_codes.ts +388 -0
  249. package/src/test/start_anvil.ts +189 -22
  250. package/src/test/upgrade_utils.ts +30 -21
  251. package/src/types.ts +71 -7
  252. package/src/utils.ts +164 -96
  253. package/src/zkPassportVerifierAddress.ts +15 -0
  254. package/dest/contracts/forwarder.d.ts +0 -24
  255. package/dest/contracts/forwarder.d.ts.map +0 -1
  256. package/dest/contracts/forwarder.js +0 -101
  257. package/dest/deploy_l1_contracts.d.ts +0 -21210
  258. package/dest/deploy_l1_contracts.d.ts.map +0 -1
  259. package/dest/deploy_l1_contracts.js +0 -687
  260. package/dest/eth_cheat_codes.d.ts +0 -147
  261. package/dest/eth_cheat_codes.d.ts.map +0 -1
  262. package/dest/eth_cheat_codes.js +0 -303
  263. package/dest/index.d.ts +0 -14
  264. package/dest/index.d.ts.map +0 -1
  265. package/dest/index.js +0 -13
  266. package/dest/l1_tx_utils.d.ts +0 -192
  267. package/dest/l1_tx_utils.d.ts.map +0 -1
  268. package/dest/l1_tx_utils.js +0 -641
  269. package/dest/l1_tx_utils_with_blobs.d.ts +0 -12
  270. package/dest/l1_tx_utils_with_blobs.d.ts.map +0 -1
  271. package/dest/l1_tx_utils_with_blobs.js +0 -64
  272. package/dest/test/delayed_tx_utils.d.ts +0 -8
  273. package/dest/test/delayed_tx_utils.d.ts.map +0 -1
  274. package/dest/test/delayed_tx_utils.js +0 -21
  275. package/dest/test/tx_delayer.d.ts +0 -25
  276. package/dest/test/tx_delayer.d.ts.map +0 -1
  277. package/dest/test/tx_delayer.js +0 -116
  278. package/src/contracts/forwarder.ts +0 -132
  279. package/src/deploy_l1_contracts.ts +0 -948
  280. package/src/eth_cheat_codes.ts +0 -314
  281. package/src/index.ts +0 -13
  282. package/src/l1_tx_utils.ts +0 -847
  283. package/src/l1_tx_utils_with_blobs.ts +0 -86
  284. package/src/test/delayed_tx_utils.ts +0 -24
  285. package/src/test/tx_delayer.ts +0 -163
@@ -1,19 +1,89 @@
1
+ import type { SlotNumber } from '@aztec/foundation/branded-types';
2
+ import type { EthAddress } from '@aztec/foundation/eth-address';
3
+ import { Signature } from '@aztec/foundation/eth-signature';
1
4
  import { EmpireBaseAbi } from '@aztec/l1-artifacts/EmpireBaseAbi';
2
5
 
3
- import { type Hex, encodeFunctionData } from 'viem';
6
+ import { type Hex, type TypedDataDefinition, encodeFunctionData } from 'viem';
4
7
 
5
- import type { L1TxRequest } from '../l1_tx_utils.js';
8
+ import type { L1TxRequest } from '../l1_tx_utils/index.js';
6
9
 
7
10
  export interface IEmpireBase {
8
- getRoundInfo(rollupAddress: Hex, round: bigint): Promise<{ lastVote: bigint; leader: Hex; executed: boolean }>;
9
- computeRound(slot: bigint): Promise<bigint>;
10
- createVoteRequest(payload: Hex): L1TxRequest;
11
+ get address(): EthAddress;
12
+ getRoundInfo(
13
+ rollupAddress: Hex,
14
+ round: bigint,
15
+ ): Promise<{ lastSignalSlot: SlotNumber; payloadWithMostSignals: Hex; quorumReached: boolean; executed: boolean }>;
16
+ computeRound(slot: SlotNumber): Promise<bigint>;
17
+ createSignalRequest(payload: Hex): L1TxRequest;
18
+ createSignalRequestWithSignature(
19
+ payload: Hex,
20
+ slot: SlotNumber,
21
+ chainId: number,
22
+ signerAddress: Hex,
23
+ signer: (msg: TypedDataDefinition) => Promise<Hex>,
24
+ ): Promise<L1TxRequest>;
11
25
  }
12
26
 
13
- export function encodeVote(payload: Hex): Hex {
27
+ export function encodeSignal(payload: Hex): Hex {
14
28
  return encodeFunctionData({
15
29
  abi: EmpireBaseAbi,
16
- functionName: 'vote',
30
+ functionName: 'signal',
17
31
  args: [payload],
18
32
  });
19
33
  }
34
+
35
+ export function encodeSignalWithSignature(payload: Hex, signature: Signature) {
36
+ return encodeFunctionData({
37
+ abi: EmpireBaseAbi,
38
+ functionName: 'signalWithSig',
39
+ args: [payload, signature.toViemSignature()],
40
+ });
41
+ }
42
+
43
+ /**
44
+ * Signs a signal proposal using EIP-712 typed data for use with signalWithSig
45
+ * @param walletClient - The viem wallet client to sign with
46
+ * @param payload - The payload address to signal
47
+ * @param verifyingContract - The address of the EmpireBase contract
48
+ * @param chainId - The chain ID where the contract is deployed
49
+ * @param account - The account to sign with (optional if hoisted on wallet client)
50
+ * @returns The EIP-712 signature
51
+ */
52
+ export async function signSignalWithSig(
53
+ signer: (msg: TypedDataDefinition) => Promise<Hex>,
54
+ payload: Hex,
55
+ slot: SlotNumber,
56
+ instance: Hex,
57
+ verifyingContract: Hex,
58
+ chainId: number,
59
+ ): Promise<Signature> {
60
+ const domain = {
61
+ name: 'EmpireBase',
62
+ version: '1',
63
+ chainId,
64
+ verifyingContract,
65
+ };
66
+
67
+ const types = {
68
+ EIP712Domain: [
69
+ { name: 'name', type: 'string' },
70
+ { name: 'version', type: 'string' },
71
+ { name: 'chainId', type: 'uint256' },
72
+ { name: 'verifyingContract', type: 'address' },
73
+ ],
74
+ Signal: [
75
+ { name: 'payload', type: 'address' },
76
+ { name: 'slot', type: 'uint256' },
77
+ { name: 'instance', type: 'address' },
78
+ ],
79
+ };
80
+
81
+ const message = {
82
+ payload,
83
+ slot: BigInt(slot),
84
+ instance,
85
+ };
86
+
87
+ const typedData = { domain, types, primaryType: 'Signal', message };
88
+ return Signature.fromString(await signer(typedData));
89
+ }
@@ -0,0 +1,13 @@
1
+ export class BlockTagTooOldError extends Error {
2
+ constructor(blockTag: bigint | number, latestBlock: bigint | number) {
3
+ super(`Block tag ${blockTag} is more than 128 blocks behind the latest block ${latestBlock}`);
4
+ this.name = 'BlockTagTooOldError';
5
+ }
6
+ }
7
+
8
+ export class NoCommitteeError extends Error {
9
+ constructor() {
10
+ super('The committee does not exist on L1');
11
+ this.name = 'NoCommitteeError';
12
+ }
13
+ }
@@ -0,0 +1,66 @@
1
+ import { EthAddress } from '@aztec/foundation/eth-address';
2
+ import { FeeAssetHandlerAbi } from '@aztec/l1-artifacts/FeeAssetHandlerAbi';
3
+
4
+ import { type Hex, encodeFunctionData, getContract } from 'viem';
5
+
6
+ import type { L1TxUtils } from '../l1_tx_utils/index.js';
7
+ import type { ViemClient } from '../types.js';
8
+
9
+ export class FeeAssetHandlerContract {
10
+ public address: EthAddress;
11
+
12
+ constructor(
13
+ public readonly client: ViemClient,
14
+ address: Hex | EthAddress,
15
+ ) {
16
+ if (address instanceof EthAddress) {
17
+ address = address.toString();
18
+ }
19
+ this.address = EthAddress.fromString(address);
20
+ }
21
+
22
+ public async getOwner(): Promise<EthAddress> {
23
+ const contract = getContract({
24
+ abi: FeeAssetHandlerAbi,
25
+ address: this.address.toString(),
26
+ client: this.client,
27
+ });
28
+ return EthAddress.fromString(await contract.read.owner());
29
+ }
30
+
31
+ public getMintAmount() {
32
+ const contract = getContract({
33
+ abi: FeeAssetHandlerAbi,
34
+ address: this.address.toString(),
35
+ client: this.client,
36
+ });
37
+ return contract.read.mintAmount();
38
+ }
39
+
40
+ public mint(txUtils: L1TxUtils, recipient: Hex | EthAddress) {
41
+ if (recipient instanceof EthAddress) {
42
+ recipient = recipient.toString();
43
+ }
44
+ return txUtils.sendAndMonitorTransaction({
45
+ to: this.address.toString(),
46
+ abi: FeeAssetHandlerAbi,
47
+ data: encodeFunctionData({
48
+ abi: FeeAssetHandlerAbi,
49
+ functionName: 'mint',
50
+ args: [recipient],
51
+ }),
52
+ });
53
+ }
54
+
55
+ public setMintAmount(txUtils: L1TxUtils, amount: bigint) {
56
+ return txUtils.sendAndMonitorTransaction({
57
+ to: this.address.toString(),
58
+ abi: FeeAssetHandlerAbi,
59
+ data: encodeFunctionData({
60
+ abi: FeeAssetHandlerAbi,
61
+ functionName: 'setMintAmount',
62
+ args: [amount],
63
+ }),
64
+ });
65
+ }
66
+ }
@@ -0,0 +1,285 @@
1
+ import { memoize } from '@aztec/foundation/decorators';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+ import { type Logger, createLogger } from '@aztec/foundation/log';
4
+
5
+ import { type Hex, encodeAbiParameters, getContract, keccak256, parseAbiParameters } from 'viem';
6
+
7
+ import type { ViemClient } from '../types.js';
8
+ import { RollupContract } from './rollup.js';
9
+
10
+ /** Maximum price modifier per checkpoint in basis points. ±100 bps = ±1% */
11
+ export const MAX_FEE_ASSET_PRICE_MODIFIER_BPS = 100n;
12
+
13
+ /**
14
+ * Validates that a fee asset price modifier is within the allowed range.
15
+ * Validators should call this before attesting to a checkpoint proposal.
16
+ *
17
+ * @param modifier - The fee asset price modifier in basis points
18
+ * @returns true if the modifier is valid (between -100 and +100 bps)
19
+ */
20
+ export function validateFeeAssetPriceModifier(modifier: bigint): boolean {
21
+ return modifier >= -MAX_FEE_ASSET_PRICE_MODIFIER_BPS && modifier <= MAX_FEE_ASSET_PRICE_MODIFIER_BPS;
22
+ }
23
+
24
+ /**
25
+ * Oracle for computing fee asset price modifiers based on Uniswap V4 pool prices.
26
+ * Only active on Ethereum mainnet - returns 0 on other chains.
27
+ */
28
+ export class FeeAssetPriceOracle {
29
+ constructor(
30
+ private client: ViemClient,
31
+ private readonly rollupContract: RollupContract,
32
+ private log: Logger = createLogger('fee-asset-price-oracle'),
33
+ ) {}
34
+
35
+ @memoize
36
+ async getUniswapOracle(): Promise<UniswapPriceOracle | undefined> {
37
+ const code = await this.client.getCode({ address: STATE_VIEW_ADDRESS.toString() });
38
+ if (code === undefined || code === '0x') {
39
+ this.log.warn('Uniswap V4 StateView contract not found, skipping fee asset price oracle');
40
+ return undefined;
41
+ }
42
+ this.log.info('Uniswap V4 StateView contract found, initializing fee asset price oracle');
43
+ const oracle = new UniswapPriceOracle(this.client, this.log);
44
+
45
+ try {
46
+ if (!(await oracle.isPoolInitialized())) {
47
+ this.log.warn('Uniswap V4 pool not initialized, skipping fee asset price oracle');
48
+ return undefined;
49
+ }
50
+ } catch (err) {
51
+ this.log.warn(`Failed to check if Uniswap V4 pool is initialized: ${err}`);
52
+ return undefined;
53
+ }
54
+
55
+ return oracle;
56
+ }
57
+
58
+ /**
59
+ * Computes the fee asset price modifier to be used in the next checkpoint proposal.
60
+ *
61
+ * The modifier adjusts the on-chain fee asset price toward the oracle price,
62
+ * clamped to ±1% (±100 basis points) per checkpoint.
63
+ *
64
+ * Returns 0 if not on mainnet or if the oracle query fails.
65
+ *
66
+ * @param currentPriceE12 - Optional override for the parent checkpoint's eth-per-fee-asset
67
+ * (E12 scale). When omitted, the latest published value is read from L1. Pipelined
68
+ * proposers should supply the predicted parent value so the modifier they emit aligns
69
+ * with the parent fee header L1 will see when the previous pipelined checkpoint lands.
70
+ * @returns The price modifier in basis points (positive to increase price, negative to decrease)
71
+ */
72
+ async computePriceModifier(currentPriceE12?: bigint): Promise<bigint> {
73
+ const uniswapOracle = await this.getUniswapOracle();
74
+ if (!uniswapOracle) {
75
+ return 0n;
76
+ }
77
+
78
+ try {
79
+ // Get current on-chain price (ETH per fee asset, E12), preferring the caller-supplied value.
80
+ const resolvedCurrentPriceE12 = currentPriceE12 ?? (await this.rollupContract.getEthPerFeeAsset());
81
+
82
+ // Get oracle price (median of last N blocks, ETH per fee asset, E12)
83
+ const oraclePriceE12 = await uniswapOracle.getMeanEthPerFeeAssetE12();
84
+
85
+ // Compute modifier in basis points
86
+ const modifier = this.computePriceModifierBps(resolvedCurrentPriceE12, oraclePriceE12);
87
+
88
+ this.log.debug('Computed price modifier', {
89
+ currentPriceE12: resolvedCurrentPriceE12.toString(),
90
+ oraclePriceE12: oraclePriceE12.toString(),
91
+ modifierBps: modifier.toString(),
92
+ currentPriceFromCaller: currentPriceE12 !== undefined,
93
+ });
94
+
95
+ return modifier;
96
+ } catch (err) {
97
+ this.log.warn(`Failed to compute price modifier, using 0: ${err}`);
98
+ return 0n;
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Gets the current oracle price (ETH per fee asset, scaled by 1e12).
104
+ * Returns undefined if not on mainnet or if the oracle query fails.
105
+ */
106
+ async getOraclePrice(): Promise<bigint | undefined> {
107
+ const uniswapOracle = await this.getUniswapOracle();
108
+ if (!uniswapOracle) {
109
+ return undefined;
110
+ }
111
+
112
+ try {
113
+ return await uniswapOracle.getMeanEthPerFeeAssetE12();
114
+ } catch (err) {
115
+ this.log.warn(`Failed to get oracle price: ${err}`);
116
+ return undefined;
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Computes the basis points modifier needed to move from current price toward target price.
122
+ *
123
+ * @param currentPrice - Current ETH per fee asset (E12 scale)
124
+ * @param targetPrice - Target ETH per fee asset (E12 scale)
125
+ * @returns Basis points modifier clamped to ±100 (±1%)
126
+ */
127
+ computePriceModifierBps(currentPrice: bigint, targetPrice: bigint): bigint {
128
+ if (currentPrice === 0n) {
129
+ return MAX_FEE_ASSET_PRICE_MODIFIER_BPS;
130
+ }
131
+
132
+ // Calculate percentage difference in basis points
133
+ // modifierBps = ((targetPrice - currentPrice) / currentPrice) * 10000
134
+ const diff = targetPrice - currentPrice;
135
+ const rawModifierBps = (diff * 10_000n) / currentPrice;
136
+
137
+ // Clamp to ±MAX_FEE_ASSET_PRICE_MODIFIER_BPS
138
+ if (rawModifierBps > MAX_FEE_ASSET_PRICE_MODIFIER_BPS) {
139
+ return MAX_FEE_ASSET_PRICE_MODIFIER_BPS;
140
+ }
141
+ if (rawModifierBps < -MAX_FEE_ASSET_PRICE_MODIFIER_BPS) {
142
+ return -MAX_FEE_ASSET_PRICE_MODIFIER_BPS;
143
+ }
144
+ return rawModifierBps;
145
+ }
146
+ }
147
+
148
+ /** Mainnet Uniswap V4 StateView contract address */
149
+ export const STATE_VIEW_ADDRESS = EthAddress.fromString('0x7ffe42c4a5deea5b0fec41c94c136cf115597227');
150
+
151
+ const PRECISION_Q192 = 10n ** 12n * 2n ** 192n;
152
+
153
+ /**
154
+ * Converts Uniswap's sqrtPriceX96 directly to ETH per FeeAsset (E12).
155
+ *
156
+ * For an ETH/FeeAsset pool where ETH is currency0 and FeeAsset is currency1:
157
+ * - Uniswap's sqrtPriceX96 = sqrt(FeeAsset/ETH) * 2^96
158
+ * - We need: ETH/FeeAsset with 1e12 precision
159
+ *
160
+ * Math:
161
+ * price = (sqrtPriceX96 / 2^96)^2 = sqrtPriceX96^2 / 2^192 (FeeAsset per ETH)
162
+ * ethPerFeeAsset = 1 / price = 2^192 / sqrtPriceX96^2
163
+ * ethPerFeeAssetE12 = ethPerFeeAsset * 1e12 = 1e12 * 2^192 / sqrtPriceX96^2
164
+ */
165
+ export function sqrtPriceX96ToEthPerFeeAssetE12(sqrtPriceX96: bigint): bigint {
166
+ if (sqrtPriceX96 === 0n) {
167
+ throw new Error('Cannot convert zero sqrtPriceX96');
168
+ }
169
+ return PRECISION_Q192 / (sqrtPriceX96 * sqrtPriceX96);
170
+ }
171
+ /**
172
+ * Uniswap V4 StateView ABI - only the functions we need
173
+ */
174
+ const StateViewAbi = [
175
+ {
176
+ type: 'function',
177
+ name: 'getSlot0',
178
+ inputs: [{ name: 'poolId', type: 'bytes32', internalType: 'PoolId' }],
179
+ outputs: [
180
+ { name: 'sqrtPriceX96', type: 'uint160', internalType: 'uint160' },
181
+ { name: 'tick', type: 'int24', internalType: 'int24' },
182
+ { name: 'protocolFee', type: 'uint24', internalType: 'uint24' },
183
+ { name: 'lpFee', type: 'uint24', internalType: 'uint24' },
184
+ ],
185
+ stateMutability: 'view',
186
+ },
187
+ ] as const;
188
+
189
+ /**
190
+ * Client for querying the ETH/FeeAsset price from Uniswap V4.
191
+ * Returns prices in ETH per FeeAsset format (E12) to match the rollup contract.
192
+ */
193
+ class UniswapPriceOracle {
194
+ private readonly stateView;
195
+ private readonly poolId: Hex;
196
+ private readonly log: Logger;
197
+
198
+ constructor(
199
+ private readonly client: ViemClient,
200
+ log?: Logger,
201
+ ) {
202
+ this.log = log ?? createLogger('uniswap-price-oracle');
203
+ this.stateView = getContract({
204
+ address: STATE_VIEW_ADDRESS.toString(),
205
+ abi: StateViewAbi,
206
+ client,
207
+ });
208
+ this.poolId = this.computePoolId();
209
+ this.log.debug(`Initialized UniswapPriceOracle with poolId: ${this.poolId}`);
210
+ }
211
+
212
+ /**
213
+ * Computes the PoolId from the pool configuration by hashing its components.
214
+ * PoolId = keccak256(abi.encode(currency0, currency1, fee, tickSpacing, hooks))
215
+ * For mainnet, the value is expected to be: 0xce2899b16743cfd5a954d8122d5e07f410305b1aebee39fd73d9f3b9ebf10c2f
216
+ * Derived anyway to make it simpler to change if needed.
217
+ */
218
+ @memoize
219
+ computePoolId(): Hex {
220
+ /** ETH/FeeAsset pool configuration (hardcoded for mainnet) */
221
+ const encoded = encodeAbiParameters(parseAbiParameters('address, address, uint24, int24, address'), [
222
+ EthAddress.ZERO.toString(),
223
+ EthAddress.fromString('0xA27EC0006e59f245217Ff08CD52A7E8b169E62D2').toString(),
224
+ 500, // 0.05%
225
+ 10,
226
+ EthAddress.fromString('0xd53006d1e3110fD319a79AEEc4c527a0d265E080').toString(),
227
+ ]);
228
+ return keccak256(encoded);
229
+ }
230
+
231
+ async isPoolInitialized(): Promise<boolean> {
232
+ const [sqrtPriceX96] = await this.stateView.read.getSlot0([this.poolId], undefined);
233
+ return sqrtPriceX96 !== 0n;
234
+ }
235
+
236
+ /**
237
+ * Gets the price as ETH per FeeAsset, scaled by 1e12.
238
+ * This is the format expected by the rollup contract.
239
+ *
240
+ * @param blockNumber - Optional block number to query at (defaults to latest)
241
+ */
242
+ async getEthPerFeeAssetE12(blockNumber?: bigint): Promise<bigint> {
243
+ const [sqrtPriceX96] = await this.stateView.read.getSlot0(
244
+ [this.poolId],
245
+ blockNumber !== undefined ? { blockNumber } : undefined,
246
+ );
247
+ return sqrtPriceX96ToEthPerFeeAssetE12(sqrtPriceX96);
248
+ }
249
+
250
+ /**
251
+ * Gets the median price over the last N blocks as ETH per FeeAsset (E12).
252
+ * Using median helps protect against single-block manipulation.
253
+ *
254
+ * @param numBlocks - Number of recent blocks to sample (default: 5)
255
+ * @returns Median price as ETH per FeeAsset, scaled by 1e12
256
+ */
257
+ async getMeanEthPerFeeAssetE12(numBlocks: number = 5): Promise<bigint> {
258
+ const currentBlock = await this.client.getBlockNumber();
259
+ const prices: bigint[] = [];
260
+
261
+ for (let i = 0; i < numBlocks; i++) {
262
+ const blockNumber = currentBlock - BigInt(i);
263
+ if (blockNumber < 0n) {
264
+ break;
265
+ }
266
+
267
+ try {
268
+ const price = await this.getEthPerFeeAssetE12(blockNumber);
269
+ prices.push(price);
270
+ } catch (err) {
271
+ this.log.warn(`Failed to get price at block ${blockNumber}: ${err}`);
272
+ // Continue with fewer samples
273
+ }
274
+ }
275
+
276
+ const filteredPrices = prices.filter(price => price !== 0n);
277
+
278
+ if (filteredPrices.length === 0) {
279
+ throw new Error('Failed to get any price samples from Uniswap oracle');
280
+ }
281
+
282
+ const mean = filteredPrices.reduce((a, b) => a + b, 0n) / BigInt(filteredPrices.length);
283
+ return mean;
284
+ }
285
+ }
@@ -1,43 +1,57 @@
1
1
  import { EthAddress } from '@aztec/foundation/eth-address';
2
- import { TestERC20Abi as FeeJuiceAbi } from '@aztec/l1-artifacts';
2
+ import { TestERC20Abi as FeeJuiceAbi } from '@aztec/l1-artifacts/TestERC20Abi';
3
3
 
4
4
  import { type GetContractReturnType, type Hex, getContract } from 'viem';
5
5
 
6
- import type { L1Clients } from '../types.js';
6
+ import { type ExtendedViemWalletClient, type ViemClient, isExtendedClient } from '../types.js';
7
7
 
8
8
  export class FeeJuiceContract {
9
- private readonly publicFeeJuice: GetContractReturnType<typeof FeeJuiceAbi, L1Clients['publicClient']>;
10
- private readonly walletFeeJuice: GetContractReturnType<typeof FeeJuiceAbi, L1Clients['walletClient']> | undefined;
9
+ private readonly feeJuiceContract: GetContractReturnType<typeof FeeJuiceAbi, ViemClient>;
11
10
 
12
11
  constructor(
13
- address: Hex,
14
- public readonly publicClient: L1Clients['publicClient'],
15
- public readonly walletClient: L1Clients['walletClient'] | undefined,
12
+ address: Hex | EthAddress,
13
+ public readonly client: ViemClient,
16
14
  ) {
17
- this.publicFeeJuice = getContract({ address, abi: FeeJuiceAbi, client: publicClient });
18
- this.walletFeeJuice = walletClient ? getContract({ address, abi: FeeJuiceAbi, client: walletClient }) : undefined;
15
+ if (address instanceof EthAddress) {
16
+ address = address.toString();
17
+ }
18
+ this.feeJuiceContract = getContract({ address, abi: FeeJuiceAbi, client });
19
19
  }
20
20
 
21
21
  public get address() {
22
- return EthAddress.fromString(this.publicFeeJuice.address);
22
+ return EthAddress.fromString(this.feeJuiceContract.address);
23
+ }
24
+
25
+ public async getOwner(): Promise<EthAddress> {
26
+ return EthAddress.fromString(await this.feeJuiceContract.read.owner());
23
27
  }
24
28
 
25
- private assertWalletFeeJuice() {
26
- if (!this.walletFeeJuice) {
29
+ private assertWalletFeeJuice(): GetContractReturnType<typeof FeeJuiceAbi, ExtendedViemWalletClient> {
30
+ if (!isExtendedClient(this.client)) {
27
31
  throw new Error('Wallet client is required for this operation');
28
32
  }
29
- return this.walletFeeJuice;
33
+ return this.feeJuiceContract as GetContractReturnType<typeof FeeJuiceAbi, ExtendedViemWalletClient>;
30
34
  }
31
35
 
32
36
  public async mint(to: Hex, amount: bigint) {
33
37
  const walletFeeJuice = this.assertWalletFeeJuice();
34
38
  const tx = await walletFeeJuice.write.mint([to, amount]);
35
- await this.publicClient.waitForTransactionReceipt({ hash: tx });
39
+ const receipt = await this.client.waitForTransactionReceipt({ hash: tx });
40
+
41
+ if (receipt.status === 'success') {
42
+ return;
43
+ }
44
+ throw new Error('Mint failed');
36
45
  }
37
46
 
38
47
  public async approve(spender: Hex, amount: bigint) {
39
48
  const walletFeeJuice = this.assertWalletFeeJuice();
40
49
  const tx = await walletFeeJuice.write.approve([spender, amount]);
41
- await this.publicClient.waitForTransactionReceipt({ hash: tx });
50
+ const receipt = await this.client.waitForTransactionReceipt({ hash: tx });
51
+
52
+ if (receipt.status === 'success') {
53
+ return;
54
+ }
55
+ throw new Error('Approve failed');
42
56
  }
43
57
  }