@aztec/ethereum 0.0.0-test.0 → 0.0.1-commit.03f7ef2

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 (272) 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 +6 -4
  6. package/dest/client.d.ts.map +1 -1
  7. package/dest/client.js +21 -3
  8. package/dest/config.d.ts +71 -16
  9. package/dest/config.d.ts.map +1 -1
  10. package/dest/config.js +138 -22
  11. package/dest/constants.d.ts +1 -1
  12. package/dest/contracts/empire_base.d.ts +25 -8
  13. package/dest/contracts/empire_base.d.ts.map +1 -1
  14. package/dest/contracts/empire_base.js +75 -2
  15. package/dest/contracts/empire_slashing_proposer.d.ts +67 -0
  16. package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -0
  17. package/dest/contracts/empire_slashing_proposer.js +209 -0
  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 +19 -0
  22. package/dest/contracts/fee_asset_handler.d.ts.map +1 -0
  23. package/dest/contracts/fee_asset_handler.js +57 -0
  24. package/dest/contracts/fee_juice.d.ts +6 -7
  25. package/dest/contracts/fee_juice.d.ts.map +1 -1
  26. package/dest/contracts/fee_juice.js +27 -20
  27. package/dest/contracts/governance.d.ts +43 -32
  28. package/dest/contracts/governance.d.ts.map +1 -1
  29. package/dest/contracts/governance.js +87 -84
  30. package/dest/contracts/governance_proposer.d.ts +17 -13
  31. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  32. package/dest/contracts/governance_proposer.js +46 -17
  33. package/dest/contracts/gse.d.ts +32 -0
  34. package/dest/contracts/gse.d.ts.map +1 -0
  35. package/dest/contracts/gse.js +72 -0
  36. package/dest/contracts/inbox.d.ts +26 -0
  37. package/dest/contracts/inbox.d.ts.map +1 -0
  38. package/dest/contracts/inbox.js +45 -0
  39. package/dest/contracts/index.d.ts +9 -3
  40. package/dest/contracts/index.d.ts.map +1 -1
  41. package/dest/contracts/index.js +8 -2
  42. package/dest/contracts/multicall.d.ts +21 -0
  43. package/dest/contracts/multicall.d.ts.map +1 -0
  44. package/dest/contracts/multicall.js +156 -0
  45. package/dest/contracts/registry.d.ts +10 -5
  46. package/dest/contracts/registry.d.ts.map +1 -1
  47. package/dest/contracts/registry.js +44 -16
  48. package/dest/contracts/rollup.d.ts +221 -41
  49. package/dest/contracts/rollup.d.ts.map +1 -1
  50. package/dest/contracts/rollup.js +549 -81
  51. package/dest/contracts/slasher_contract.d.ts +44 -0
  52. package/dest/contracts/slasher_contract.d.ts.map +1 -0
  53. package/dest/contracts/slasher_contract.js +75 -0
  54. package/dest/contracts/tally_slashing_proposer.d.ts +140 -0
  55. package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -0
  56. package/dest/contracts/tally_slashing_proposer.js +313 -0
  57. package/dest/contracts/utils.d.ts +3 -0
  58. package/dest/contracts/utils.d.ts.map +1 -0
  59. package/dest/contracts/utils.js +11 -0
  60. package/dest/deploy_aztec_l1_contracts.d.ts +245 -0
  61. package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
  62. package/dest/deploy_aztec_l1_contracts.js +335 -0
  63. package/dest/deploy_l1_contract.d.ts +68 -0
  64. package/dest/deploy_l1_contract.d.ts.map +1 -0
  65. package/dest/deploy_l1_contract.js +312 -0
  66. package/dest/eth-signer/eth-signer.d.ts +21 -0
  67. package/dest/eth-signer/eth-signer.d.ts.map +1 -0
  68. package/dest/eth-signer/eth-signer.js +5 -0
  69. package/dest/eth-signer/index.d.ts +2 -0
  70. package/dest/eth-signer/index.d.ts.map +1 -0
  71. package/dest/eth-signer/index.js +1 -0
  72. package/dest/forwarder_proxy.d.ts +32 -0
  73. package/dest/forwarder_proxy.d.ts.map +1 -0
  74. package/dest/forwarder_proxy.js +93 -0
  75. package/dest/l1_artifacts.d.ts +77364 -0
  76. package/dest/l1_artifacts.d.ts.map +1 -0
  77. package/dest/l1_artifacts.js +166 -0
  78. package/dest/l1_contract_addresses.d.ts +24 -4
  79. package/dest/l1_contract_addresses.d.ts.map +1 -1
  80. package/dest/l1_contract_addresses.js +25 -21
  81. package/dest/l1_reader.d.ts +4 -2
  82. package/dest/l1_reader.d.ts.map +1 -1
  83. package/dest/l1_reader.js +14 -8
  84. package/dest/l1_tx_utils/config.d.ts +59 -0
  85. package/dest/l1_tx_utils/config.d.ts.map +1 -0
  86. package/dest/l1_tx_utils/config.js +96 -0
  87. package/dest/l1_tx_utils/constants.d.ts +12 -0
  88. package/dest/l1_tx_utils/constants.d.ts.map +1 -0
  89. package/dest/l1_tx_utils/constants.js +39 -0
  90. package/dest/l1_tx_utils/factory.d.ts +24 -0
  91. package/dest/l1_tx_utils/factory.d.ts.map +1 -0
  92. package/dest/l1_tx_utils/factory.js +12 -0
  93. package/dest/l1_tx_utils/fee-strategies/index.d.ts +9 -0
  94. package/dest/l1_tx_utils/fee-strategies/index.d.ts.map +1 -0
  95. package/dest/l1_tx_utils/fee-strategies/index.js +11 -0
  96. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts +18 -0
  97. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts.map +1 -0
  98. package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +111 -0
  99. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts +32 -0
  100. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts.map +1 -0
  101. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +173 -0
  102. package/dest/l1_tx_utils/fee-strategies/types.d.ts +64 -0
  103. package/dest/l1_tx_utils/fee-strategies/types.d.ts.map +1 -0
  104. package/dest/l1_tx_utils/fee-strategies/types.js +24 -0
  105. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +41 -0
  106. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -0
  107. package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +48 -0
  108. package/dest/l1_tx_utils/index-blobs.d.ts +3 -0
  109. package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -0
  110. package/dest/l1_tx_utils/index-blobs.js +2 -0
  111. package/dest/l1_tx_utils/index.d.ts +12 -0
  112. package/dest/l1_tx_utils/index.d.ts.map +1 -0
  113. package/dest/l1_tx_utils/index.js +12 -0
  114. package/dest/l1_tx_utils/interfaces.d.ts +76 -0
  115. package/dest/l1_tx_utils/interfaces.d.ts.map +1 -0
  116. package/dest/l1_tx_utils/interfaces.js +4 -0
  117. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +233 -0
  118. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -0
  119. package/dest/l1_tx_utils/l1_fee_analyzer.js +506 -0
  120. package/dest/l1_tx_utils/l1_tx_utils.d.ts +94 -0
  121. package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -0
  122. package/dest/l1_tx_utils/l1_tx_utils.js +623 -0
  123. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +26 -0
  124. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +1 -0
  125. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +26 -0
  126. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +87 -0
  127. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -0
  128. package/dest/l1_tx_utils/readonly_l1_tx_utils.js +360 -0
  129. package/dest/l1_tx_utils/signer.d.ts +4 -0
  130. package/dest/l1_tx_utils/signer.d.ts.map +1 -0
  131. package/dest/l1_tx_utils/signer.js +16 -0
  132. package/dest/l1_tx_utils/types.d.ts +67 -0
  133. package/dest/l1_tx_utils/types.d.ts.map +1 -0
  134. package/dest/l1_tx_utils/types.js +26 -0
  135. package/dest/l1_tx_utils/utils.d.ts +4 -0
  136. package/dest/l1_tx_utils/utils.d.ts.map +1 -0
  137. package/dest/l1_tx_utils/utils.js +14 -0
  138. package/dest/l1_types.d.ts +6 -0
  139. package/dest/l1_types.d.ts.map +1 -0
  140. package/dest/l1_types.js +1 -0
  141. package/dest/publisher_manager.d.ts +15 -0
  142. package/dest/publisher_manager.d.ts.map +1 -0
  143. package/dest/publisher_manager.js +88 -0
  144. package/dest/queries.d.ts +4 -2
  145. package/dest/queries.d.ts.map +1 -1
  146. package/dest/queries.js +53 -12
  147. package/dest/test/chain_monitor.d.ts +75 -0
  148. package/dest/test/chain_monitor.d.ts.map +1 -0
  149. package/dest/test/chain_monitor.js +214 -0
  150. package/dest/test/delayed_tx_utils.d.ts +8 -3
  151. package/dest/test/delayed_tx_utils.d.ts.map +1 -1
  152. package/dest/test/delayed_tx_utils.js +13 -6
  153. package/dest/test/eth_cheat_codes.d.ts +217 -0
  154. package/dest/test/eth_cheat_codes.d.ts.map +1 -0
  155. package/dest/test/eth_cheat_codes.js +560 -0
  156. package/dest/test/eth_cheat_codes_with_state.d.ts +2 -2
  157. package/dest/test/eth_cheat_codes_with_state.d.ts.map +1 -1
  158. package/dest/test/eth_cheat_codes_with_state.js +1 -1
  159. package/dest/test/index.d.ts +4 -1
  160. package/dest/test/index.d.ts.map +1 -1
  161. package/dest/test/index.js +3 -0
  162. package/dest/test/rollup_cheat_codes.d.ts +87 -0
  163. package/dest/test/rollup_cheat_codes.d.ts.map +1 -0
  164. package/dest/test/rollup_cheat_codes.js +275 -0
  165. package/dest/test/start_anvil.d.ts +9 -1
  166. package/dest/test/start_anvil.d.ts.map +1 -1
  167. package/dest/test/start_anvil.js +16 -7
  168. package/dest/test/tx_delayer.d.ts +18 -7
  169. package/dest/test/tx_delayer.d.ts.map +1 -1
  170. package/dest/test/tx_delayer.js +97 -20
  171. package/dest/test/upgrade_utils.d.ts +6 -5
  172. package/dest/test/upgrade_utils.d.ts.map +1 -1
  173. package/dest/test/upgrade_utils.js +23 -16
  174. package/dest/types.d.ts +62 -8
  175. package/dest/types.d.ts.map +1 -1
  176. package/dest/types.js +3 -1
  177. package/dest/utils.d.ts +16 -3
  178. package/dest/utils.d.ts.map +1 -1
  179. package/dest/utils.js +61 -88
  180. package/dest/zkPassportVerifierAddress.d.ts +15 -0
  181. package/dest/zkPassportVerifierAddress.d.ts.map +1 -0
  182. package/dest/zkPassportVerifierAddress.js +11 -0
  183. package/package.json +50 -23
  184. package/src/account.ts +5 -0
  185. package/src/client.ts +43 -5
  186. package/src/config.ts +188 -31
  187. package/src/contracts/empire_base.ts +77 -7
  188. package/src/contracts/empire_slashing_proposer.ts +270 -0
  189. package/src/contracts/errors.ts +13 -0
  190. package/src/contracts/fee_asset_handler.ts +63 -0
  191. package/src/contracts/fee_juice.ts +29 -15
  192. package/src/contracts/governance.ts +80 -77
  193. package/src/contracts/governance_proposer.ts +71 -24
  194. package/src/contracts/gse.ts +88 -0
  195. package/src/contracts/inbox.ts +63 -0
  196. package/src/contracts/index.ts +8 -2
  197. package/src/contracts/multicall.ts +155 -0
  198. package/src/contracts/registry.ts +51 -26
  199. package/src/contracts/rollup.ts +624 -78
  200. package/src/contracts/slasher_contract.ts +89 -0
  201. package/src/contracts/tally_slashing_proposer.ts +318 -0
  202. package/src/contracts/utils.ts +14 -0
  203. package/src/deploy_aztec_l1_contracts.ts +556 -0
  204. package/src/deploy_l1_contract.ts +362 -0
  205. package/src/eth-signer/eth-signer.ts +25 -0
  206. package/src/eth-signer/index.ts +1 -0
  207. package/src/forwarder_proxy.ts +108 -0
  208. package/src/l1_artifacts.ts +254 -0
  209. package/src/l1_contract_addresses.ts +49 -34
  210. package/src/l1_reader.ts +17 -9
  211. package/src/l1_tx_utils/README.md +177 -0
  212. package/src/l1_tx_utils/config.ts +161 -0
  213. package/src/l1_tx_utils/constants.ts +29 -0
  214. package/src/l1_tx_utils/factory.ts +64 -0
  215. package/src/l1_tx_utils/fee-strategies/index.ts +22 -0
  216. package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +159 -0
  217. package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +241 -0
  218. package/src/l1_tx_utils/fee-strategies/types.ts +88 -0
  219. package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +119 -0
  220. package/src/l1_tx_utils/index-blobs.ts +2 -0
  221. package/src/l1_tx_utils/index.ts +14 -0
  222. package/src/l1_tx_utils/interfaces.ts +86 -0
  223. package/src/l1_tx_utils/l1_fee_analyzer.ts +804 -0
  224. package/src/l1_tx_utils/l1_tx_utils.ts +738 -0
  225. package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +77 -0
  226. package/src/l1_tx_utils/readonly_l1_tx_utils.ts +458 -0
  227. package/src/l1_tx_utils/signer.ts +28 -0
  228. package/src/l1_tx_utils/types.ts +85 -0
  229. package/src/l1_tx_utils/utils.ts +16 -0
  230. package/src/l1_types.ts +6 -0
  231. package/src/publisher_manager.ts +106 -0
  232. package/src/queries.ts +73 -15
  233. package/src/test/chain_monitor.ts +245 -0
  234. package/src/test/delayed_tx_utils.ts +34 -6
  235. package/src/test/eth_cheat_codes.ts +588 -0
  236. package/src/test/eth_cheat_codes_with_state.ts +1 -1
  237. package/src/test/index.ts +3 -0
  238. package/src/test/rollup_cheat_codes.ts +312 -0
  239. package/src/test/start_anvil.ts +24 -5
  240. package/src/test/tx_delayer.ts +130 -27
  241. package/src/test/upgrade_utils.ts +30 -21
  242. package/src/types.ts +71 -7
  243. package/src/utils.ts +79 -91
  244. package/src/zkPassportVerifierAddress.ts +15 -0
  245. package/dest/contracts/forwarder.d.ts +0 -24
  246. package/dest/contracts/forwarder.d.ts.map +0 -1
  247. package/dest/contracts/forwarder.js +0 -101
  248. package/dest/contracts/slashing_proposer.d.ts +0 -21
  249. package/dest/contracts/slashing_proposer.d.ts.map +0 -1
  250. package/dest/contracts/slashing_proposer.js +0 -47
  251. package/dest/deploy_l1_contracts.d.ts +0 -21210
  252. package/dest/deploy_l1_contracts.d.ts.map +0 -1
  253. package/dest/deploy_l1_contracts.js +0 -687
  254. package/dest/eth_cheat_codes.d.ts +0 -147
  255. package/dest/eth_cheat_codes.d.ts.map +0 -1
  256. package/dest/eth_cheat_codes.js +0 -303
  257. package/dest/index.d.ts +0 -14
  258. package/dest/index.d.ts.map +0 -1
  259. package/dest/index.js +0 -13
  260. package/dest/l1_tx_utils.d.ts +0 -192
  261. package/dest/l1_tx_utils.d.ts.map +0 -1
  262. package/dest/l1_tx_utils.js +0 -641
  263. package/dest/l1_tx_utils_with_blobs.d.ts +0 -12
  264. package/dest/l1_tx_utils_with_blobs.d.ts.map +0 -1
  265. package/dest/l1_tx_utils_with_blobs.js +0 -64
  266. package/src/contracts/forwarder.ts +0 -132
  267. package/src/contracts/slashing_proposer.ts +0 -51
  268. package/src/deploy_l1_contracts.ts +0 -948
  269. package/src/eth_cheat_codes.ts +0 -314
  270. package/src/index.ts +0 -13
  271. package/src/l1_tx_utils.ts +0 -847
  272. package/src/l1_tx_utils_with_blobs.ts +0 -86
@@ -0,0 +1,270 @@
1
+ import { SlotNumber } from '@aztec/foundation/branded-types';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+ import { createLogger } from '@aztec/foundation/log';
4
+ import { retryUntil } from '@aztec/foundation/retry';
5
+ import { EmpireSlashingProposerAbi } from '@aztec/l1-artifacts/EmpireSlashingProposerAbi';
6
+
7
+ import EventEmitter from 'events';
8
+ import {
9
+ type EncodeFunctionDataParameters,
10
+ type GetContractReturnType,
11
+ type Hex,
12
+ type Log,
13
+ type TypedDataDefinition,
14
+ encodeFunctionData,
15
+ getContract,
16
+ } from 'viem';
17
+
18
+ import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
19
+ import type { ViemClient } from '../types.js';
20
+ import { FormattedViemError, tryExtractEvent } from '../utils.js';
21
+ import { type IEmpireBase, encodeSignal, encodeSignalWithSignature, signSignalWithSig } from './empire_base.js';
22
+
23
+ export class ProposalAlreadyExecutedError extends Error {
24
+ constructor(round: bigint) {
25
+ super(`Proposal already executed: ${round}`);
26
+ }
27
+ }
28
+
29
+ export class EmpireSlashingProposerContract extends EventEmitter implements IEmpireBase {
30
+ private readonly logger = createLogger('ethereum:contracts:empire_slashing_proposer');
31
+ private readonly proposer: GetContractReturnType<typeof EmpireSlashingProposerAbi, ViemClient>;
32
+
33
+ public readonly type = 'empire' as const;
34
+
35
+ constructor(
36
+ public readonly client: ViemClient,
37
+ address: Hex | EthAddress,
38
+ ) {
39
+ super();
40
+ this.proposer = getContract({
41
+ address: typeof address === 'string' ? address : address.toString(),
42
+ abi: EmpireSlashingProposerAbi,
43
+ client,
44
+ });
45
+ }
46
+
47
+ public get address() {
48
+ return EthAddress.fromString(this.proposer.address);
49
+ }
50
+
51
+ public getQuorumSize() {
52
+ return this.proposer.read.QUORUM_SIZE();
53
+ }
54
+
55
+ public getRoundSize() {
56
+ return this.proposer.read.ROUND_SIZE();
57
+ }
58
+
59
+ public getLifetimeInRounds() {
60
+ return this.proposer.read.LIFETIME_IN_ROUNDS();
61
+ }
62
+
63
+ public getExecutionDelayInRounds() {
64
+ return this.proposer.read.EXECUTION_DELAY_IN_ROUNDS();
65
+ }
66
+
67
+ public getCurrentRound() {
68
+ return this.proposer.read.getCurrentRound();
69
+ }
70
+
71
+ public computeRound(slot: SlotNumber): Promise<bigint> {
72
+ return this.proposer.read.computeRound([BigInt(slot)]);
73
+ }
74
+
75
+ public getInstance() {
76
+ return this.proposer.read.getInstance();
77
+ }
78
+
79
+ public async getRoundInfo(
80
+ rollupAddress: Hex,
81
+ round: bigint,
82
+ ): Promise<{ lastSignalSlot: SlotNumber; payloadWithMostSignals: Hex; quorumReached: boolean; executed: boolean }> {
83
+ const result = await this.proposer.read.getRoundData([rollupAddress, round]);
84
+ const [signalCount, quorum] = await Promise.all([
85
+ this.proposer.read.signalCount([rollupAddress, round, result.payloadWithMostSignals]),
86
+ this.getQuorumSize(),
87
+ ]);
88
+ return {
89
+ lastSignalSlot: SlotNumber.fromBigInt(result.lastSignalSlot),
90
+ payloadWithMostSignals: result.payloadWithMostSignals,
91
+ quorumReached: signalCount >= quorum,
92
+ executed: result.executed,
93
+ };
94
+ }
95
+
96
+ public getPayloadSignals(rollupAddress: Hex, round: bigint, payload: Hex): Promise<bigint> {
97
+ return this.proposer.read.signalCount([rollupAddress, round, payload]);
98
+ }
99
+
100
+ public createSignalRequest(payload: Hex): L1TxRequest {
101
+ return {
102
+ to: this.address.toString(),
103
+ data: encodeSignal(payload),
104
+ };
105
+ }
106
+
107
+ public async createSignalRequestWithSignature(
108
+ payload: Hex,
109
+ slot: SlotNumber,
110
+ chainId: number,
111
+ signerAddress: Hex,
112
+ signer: (msg: TypedDataDefinition) => Promise<Hex>,
113
+ ): Promise<L1TxRequest> {
114
+ const signature = await signSignalWithSig(
115
+ signer,
116
+ payload,
117
+ slot,
118
+ await this.getInstance(),
119
+ this.address.toString(),
120
+ chainId,
121
+ );
122
+ return {
123
+ to: this.address.toString(),
124
+ data: encodeSignalWithSignature(payload, signature),
125
+ };
126
+ }
127
+
128
+ public listenToSubmittablePayloads(callback: (args: { payload: `0x${string}`; round: bigint }) => unknown) {
129
+ return this.proposer.watchEvent.PayloadSubmittable(
130
+ {},
131
+ {
132
+ strict: true,
133
+ onLogs: logs => {
134
+ for (const log of logs) {
135
+ const { payload, round } = log.args;
136
+ if (payload && round) {
137
+ callback({ payload, round });
138
+ }
139
+ }
140
+ },
141
+ },
142
+ );
143
+ }
144
+
145
+ public listenToPayloadSubmitted(callback: (args: { round: bigint; payload: `0x${string}` }) => unknown) {
146
+ return this.proposer.watchEvent.PayloadSubmitted(
147
+ {},
148
+ {
149
+ onLogs: logs => {
150
+ for (const log of logs) {
151
+ const { payload, round } = log.args;
152
+ if (round && payload) {
153
+ callback({ round, payload });
154
+ }
155
+ }
156
+ },
157
+ },
158
+ );
159
+ }
160
+
161
+ public listenToSignalCasted(
162
+ callback: (args: { round: bigint; payload: `0x${string}`; signaler: `0x${string}` }) => unknown,
163
+ ) {
164
+ return this.proposer.watchEvent.SignalCast(
165
+ {},
166
+ {
167
+ onLogs: logs => {
168
+ for (const log of logs) {
169
+ const { round, payload, signaler } = log.args;
170
+ if (round && payload && signaler) {
171
+ callback({ round, payload, signaler });
172
+ }
173
+ }
174
+ },
175
+ },
176
+ );
177
+ }
178
+
179
+ /** Creates an L1TxRequest to submit the round winner for the given round. */
180
+ public buildExecuteRoundRequest(round: bigint): L1TxRequest {
181
+ return {
182
+ to: this.address.toString(),
183
+ data: encodeFunctionData({
184
+ abi: EmpireSlashingProposerAbi,
185
+ functionName: 'submitRoundWinner',
186
+ args: [round],
187
+ }),
188
+ };
189
+ }
190
+
191
+ /** Tries to extract a PayloadSubmitted event from the given logs. */
192
+ public tryExtractPayloadSubmittedEvent(logs: Log[]) {
193
+ return tryExtractEvent(logs, this.address.toString(), EmpireSlashingProposerAbi, 'PayloadSubmitted');
194
+ }
195
+
196
+ /**
197
+ * Wait for a round to be reached.
198
+ *
199
+ * @param round - The round to wait for.
200
+ * @param pollingIntervalSeconds - The interval in seconds to poll for the round.
201
+ * @returns True if the round was reached, false otherwise.
202
+ */
203
+ public waitForRound(round: bigint, pollingIntervalSeconds: number = 1): Promise<boolean> {
204
+ return retryUntil(
205
+ async () => {
206
+ const currentRound = await this.proposer.read.getCurrentRound().catch(e => {
207
+ this.logger.error('Error getting current round', e);
208
+ return undefined;
209
+ });
210
+ return currentRound !== undefined && currentRound >= round;
211
+ },
212
+ `Waiting for round ${round} to be reached`,
213
+ 0, // no timeout
214
+ pollingIntervalSeconds,
215
+ ).catch(() => false);
216
+ }
217
+
218
+ public async executeRound(
219
+ txUtils: L1TxUtils,
220
+ round: bigint | number,
221
+ ): ReturnType<typeof txUtils.sendAndMonitorTransaction> {
222
+ if (typeof round === 'number') {
223
+ round = BigInt(round);
224
+ }
225
+ const args: EncodeFunctionDataParameters<typeof EmpireSlashingProposerAbi, 'submitRoundWinner'> = {
226
+ abi: EmpireSlashingProposerAbi,
227
+ functionName: 'submitRoundWinner',
228
+ args: [round],
229
+ };
230
+ const data = encodeFunctionData(args);
231
+ const response = await txUtils
232
+ .sendAndMonitorTransaction(
233
+ {
234
+ to: this.address.toString(),
235
+ data,
236
+ },
237
+ {
238
+ // Gas estimation is way off for this, likely because we are creating the contract/selector to call
239
+ // for the actual slashing dynamically.
240
+ gasLimitBufferPercentage: 50, // +50% gas
241
+ },
242
+ )
243
+ .catch(err => {
244
+ if (err instanceof FormattedViemError && err.message.includes('ProposalAlreadyExecuted')) {
245
+ throw new ProposalAlreadyExecutedError(round);
246
+ }
247
+ throw err;
248
+ });
249
+
250
+ if (response.receipt.status === 'reverted') {
251
+ const error = await txUtils.tryGetErrorFromRevertedTx(
252
+ data,
253
+ {
254
+ ...args,
255
+ address: this.address.toString(),
256
+ },
257
+ undefined,
258
+ [],
259
+ );
260
+ if (error?.includes('ProposalAlreadyExecuted')) {
261
+ throw new ProposalAlreadyExecutedError(round);
262
+ }
263
+ const errorMessage = `Failed to execute round ${round}, TxHash: ${response.receipt.transactionHash}, Error: ${
264
+ error ?? 'Unknown error'
265
+ }`;
266
+ throw new Error(errorMessage);
267
+ }
268
+ return response;
269
+ }
270
+ }
@@ -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,63 @@
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
+
8
+ export class FeeAssetHandlerContract {
9
+ public address: EthAddress;
10
+
11
+ constructor(
12
+ address: Hex | EthAddress,
13
+ public readonly txUtils: L1TxUtils,
14
+ ) {
15
+ if (address instanceof EthAddress) {
16
+ address = address.toString();
17
+ }
18
+ this.address = EthAddress.fromString(address);
19
+ }
20
+
21
+ public async getOwner(): Promise<EthAddress> {
22
+ const contract = getContract({
23
+ abi: FeeAssetHandlerAbi,
24
+ address: this.address.toString(),
25
+ client: this.txUtils.client,
26
+ });
27
+ return EthAddress.fromString(await contract.read.owner());
28
+ }
29
+
30
+ public getMintAmount() {
31
+ const contract = getContract({
32
+ abi: FeeAssetHandlerAbi,
33
+ address: this.address.toString(),
34
+ client: this.txUtils.client,
35
+ });
36
+ return contract.read.mintAmount();
37
+ }
38
+
39
+ public mint(recipient: Hex | EthAddress) {
40
+ if (recipient instanceof EthAddress) {
41
+ recipient = recipient.toString();
42
+ }
43
+ return this.txUtils.sendAndMonitorTransaction({
44
+ to: this.address.toString(),
45
+ data: encodeFunctionData({
46
+ abi: FeeAssetHandlerAbi,
47
+ functionName: 'mint',
48
+ args: [recipient],
49
+ }),
50
+ });
51
+ }
52
+
53
+ public setMintAmount(amount: bigint) {
54
+ return this.txUtils.sendAndMonitorTransaction({
55
+ to: this.address.toString(),
56
+ data: encodeFunctionData({
57
+ abi: FeeAssetHandlerAbi,
58
+ functionName: 'setMintAmount',
59
+ args: [amount],
60
+ }),
61
+ });
62
+ }
63
+ }
@@ -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
  }
@@ -1,20 +1,21 @@
1
1
  import { EthAddress } from '@aztec/foundation/eth-address';
2
2
  import type { Logger } from '@aztec/foundation/log';
3
3
  import { sleep } from '@aztec/foundation/sleep';
4
- import { GovernanceAbi } from '@aztec/l1-artifacts';
4
+ import { GovernanceAbi } from '@aztec/l1-artifacts/GovernanceAbi';
5
5
 
6
6
  import {
7
7
  type EncodeFunctionDataParameters,
8
8
  type GetContractReturnType,
9
9
  type Hex,
10
+ type Log,
10
11
  encodeFunctionData,
11
12
  getContract,
13
+ parseEventLogs,
12
14
  } from 'viem';
13
15
 
14
16
  import type { L1ContractAddresses } from '../l1_contract_addresses.js';
15
- import { L1TxUtils } from '../l1_tx_utils.js';
16
- import type { ViemPublicClient, ViemWalletClient } from '../types.js';
17
- import { GovernanceProposerContract } from './governance_proposer.js';
17
+ import { createL1TxUtilsFromViemWallet } from '../l1_tx_utils/index.js';
18
+ import { type ExtendedViemWalletClient, type ViemClient, isExtendedClient } from '../types.js';
18
19
 
19
20
  export type L1GovernanceContractAddresses = Pick<
20
21
  L1ContractAddresses,
@@ -33,87 +34,54 @@ export enum ProposalState {
33
34
  Expired,
34
35
  }
35
36
 
36
- export class GovernanceContract {
37
- private readonly publicGovernance: GetContractReturnType<typeof GovernanceAbi, ViemPublicClient>;
38
- private readonly walletGovernance: GetContractReturnType<typeof GovernanceAbi, ViemWalletClient> | undefined;
37
+ export function extractProposalIdFromLogs(logs: Log[]): bigint {
38
+ const parsedLogs = parseEventLogs({
39
+ abi: GovernanceAbi,
40
+ logs: logs,
41
+ eventName: 'Proposed',
42
+ });
43
+
44
+ if (parsedLogs.length === 0) {
45
+ throw new Error('Proposal log not found');
46
+ }
47
+ return parsedLogs[0].args.proposalId;
48
+ }
49
+
50
+ export class ReadOnlyGovernanceContract {
51
+ protected readonly governanceContract: GetContractReturnType<typeof GovernanceAbi, ViemClient>;
39
52
 
40
53
  constructor(
41
54
  address: Hex,
42
- public readonly publicClient: ViemPublicClient,
43
- public readonly walletClient: ViemWalletClient | undefined,
55
+ public readonly client: ViemClient,
44
56
  ) {
45
- this.publicGovernance = getContract({ address, abi: GovernanceAbi, client: publicClient });
46
- this.walletGovernance = walletClient
47
- ? getContract({ address, abi: GovernanceAbi, client: walletClient })
48
- : undefined;
57
+ this.governanceContract = getContract({ address, abi: GovernanceAbi, client: client });
49
58
  }
50
59
 
51
60
  public get address() {
52
- return EthAddress.fromString(this.publicGovernance.address);
61
+ return EthAddress.fromString(this.governanceContract.address);
53
62
  }
54
63
 
55
- public async getProposer() {
56
- const governanceProposerAddress = EthAddress.fromString(await this.publicGovernance.read.governanceProposer());
57
- return new GovernanceProposerContract(this.publicClient, governanceProposerAddress.toString());
64
+ public async getGovernanceProposerAddress() {
65
+ return EthAddress.fromString(await this.governanceContract.read.governanceProposer());
58
66
  }
59
67
 
60
- public async getGovernanceAddresses(): Promise<L1GovernanceContractAddresses> {
61
- const governanceProposer = await this.getProposer();
62
- const [rollupAddress, registryAddress] = await Promise.all([
63
- governanceProposer.getRollupAddress(),
64
- governanceProposer.getRegistryAddress(),
65
- ]);
66
- return {
67
- governanceAddress: this.address,
68
- rollupAddress,
69
- registryAddress,
70
- governanceProposerAddress: governanceProposer.address,
71
- };
68
+ public getConfiguration() {
69
+ return this.governanceContract.read.getConfiguration();
72
70
  }
73
71
 
74
72
  public getProposal(proposalId: bigint) {
75
- return this.publicGovernance.read.getProposal([proposalId]);
73
+ return this.governanceContract.read.getProposal([proposalId]);
76
74
  }
77
75
 
78
76
  public async getProposalState(proposalId: bigint): Promise<ProposalState> {
79
- const state = await this.publicGovernance.read.getProposalState([proposalId]);
77
+ const state = await this.governanceContract.read.getProposalState([proposalId]);
78
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
80
79
  if (state < 0 || state > ProposalState.Expired) {
81
80
  throw new Error(`Invalid proposal state: ${state}`);
82
81
  }
83
82
  return state as ProposalState;
84
83
  }
85
84
 
86
- private assertWalletGovernance(): NonNullable<typeof this.walletGovernance> {
87
- if (!this.walletGovernance) {
88
- throw new Error('Wallet client is required for this operation');
89
- }
90
- return this.walletGovernance;
91
- }
92
-
93
- public async deposit(onBehalfOf: Hex, amount: bigint) {
94
- const walletGovernance = this.assertWalletGovernance();
95
- const depositTx = await walletGovernance.write.deposit([onBehalfOf, amount]);
96
- await this.publicClient.waitForTransactionReceipt({ hash: depositTx });
97
- }
98
-
99
- public async proposeWithLock({
100
- payloadAddress,
101
- withdrawAddress,
102
- }: {
103
- payloadAddress: Hex;
104
- withdrawAddress: Hex;
105
- }): Promise<number> {
106
- const walletGovernance = this.assertWalletGovernance();
107
- const proposeTx = await walletGovernance.write.proposeWithLock([payloadAddress, withdrawAddress]);
108
- const receipt = await this.publicClient.waitForTransactionReceipt({ hash: proposeTx });
109
- if (receipt.status !== 'success') {
110
- throw new Error(`Proposal failed: ${receipt.status}`);
111
- }
112
-
113
- const proposalId = Number(receipt.logs[1].topics[1]);
114
- return proposalId;
115
- }
116
-
117
85
  public async awaitProposalActive({ proposalId, logger }: { proposalId: bigint; logger: Logger }) {
118
86
  const state = await this.getProposalState(proposalId);
119
87
  if (state === ProposalState.Active) {
@@ -123,7 +91,7 @@ export class GovernanceContract {
123
91
  } else {
124
92
  const proposal = await this.getProposal(proposalId);
125
93
  const startOfActive = proposal.creation + proposal.config.votingDelay;
126
- const block = await this.publicClient.getBlock();
94
+ const block = await this.client.getBlock();
127
95
  // Add 12 seconds to the time to make sure we don't vote too early
128
96
  const secondsToActive = Number(startOfActive - block.timestamp) + 12;
129
97
  const now = new Date();
@@ -151,7 +119,7 @@ export class GovernanceContract {
151
119
  proposal.config.votingDelay +
152
120
  proposal.config.votingDuration +
153
121
  proposal.config.executionDelay;
154
- const block = await this.publicClient.getBlock();
122
+ const block = await this.client.getBlock();
155
123
  const secondsToExecutable = Number(startOfExecutable - block.timestamp) + 12;
156
124
  const now = new Date();
157
125
  logger.info(`
@@ -162,11 +130,48 @@ export class GovernanceContract {
162
130
  await sleep(secondsToExecutable * 1000);
163
131
  }
164
132
  }
133
+ }
134
+
135
+ export class GovernanceContract extends ReadOnlyGovernanceContract {
136
+ protected override readonly governanceContract: GetContractReturnType<typeof GovernanceAbi, ExtendedViemWalletClient>;
137
+
138
+ constructor(
139
+ address: Hex | EthAddress,
140
+ public override readonly client: ExtendedViemWalletClient,
141
+ ) {
142
+ if (address instanceof EthAddress) {
143
+ address = address.toString();
144
+ }
145
+ super(address, client);
146
+ if (!isExtendedClient(client)) {
147
+ throw new Error('GovernanceContract has to be instantiated with a wallet client.');
148
+ }
149
+ this.governanceContract = getContract({ address, abi: GovernanceAbi, client });
150
+ }
151
+
152
+ public async deposit(onBehalfOf: Hex, amount: bigint) {
153
+ const depositTx = await this.governanceContract.write.deposit([onBehalfOf, amount]);
154
+ await this.client.waitForTransactionReceipt({ hash: depositTx });
155
+ }
156
+
157
+ public async proposeWithLock({
158
+ payloadAddress,
159
+ withdrawAddress,
160
+ }: {
161
+ payloadAddress: Hex;
162
+ withdrawAddress: Hex;
163
+ }): Promise<bigint> {
164
+ const proposeTx = await this.governanceContract.write.proposeWithLock([payloadAddress, withdrawAddress]);
165
+ const receipt = await this.client.waitForTransactionReceipt({ hash: proposeTx });
166
+ if (receipt.status !== 'success') {
167
+ throw new Error(`Proposal failed: ${receipt.status}`);
168
+ }
169
+ return extractProposalIdFromLogs(receipt.logs);
170
+ }
165
171
 
166
172
  public async getPower(): Promise<bigint> {
167
- const walletGovernance = this.assertWalletGovernance();
168
- const now = await this.publicClient.getBlock();
169
- return walletGovernance.read.powerAt([this.walletClient!.account.address, now.timestamp]);
173
+ const now = await this.client.getBlock();
174
+ return this.governanceContract.read.powerAt([this.client.account.address, now.timestamp]);
170
175
  }
171
176
 
172
177
  public async vote({
@@ -182,8 +187,7 @@ export class GovernanceContract {
182
187
  retries: number;
183
188
  logger: Logger;
184
189
  }) {
185
- const walletGovernance = this.assertWalletGovernance();
186
- const l1TxUtils = new L1TxUtils(this.publicClient, this.walletClient!, logger);
190
+ const l1TxUtils = createL1TxUtilsFromViemWallet(this.client, { logger });
187
191
  const retryDelaySeconds = 12;
188
192
 
189
193
  voteAmount = voteAmount ?? (await this.getPower());
@@ -199,7 +203,7 @@ export class GovernanceContract {
199
203
  const encodedVoteData = encodeFunctionData(voteFunctionData);
200
204
 
201
205
  const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
202
- to: walletGovernance.address,
206
+ to: this.governanceContract.address,
203
207
  data: encodedVoteData,
204
208
  });
205
209
 
@@ -209,7 +213,7 @@ export class GovernanceContract {
209
213
  } else {
210
214
  const args = {
211
215
  ...voteFunctionData,
212
- address: walletGovernance.address,
216
+ address: this.governanceContract.address,
213
217
  };
214
218
  const errorMsg = await l1TxUtils.tryGetErrorFromRevertedTx(encodedVoteData, args, undefined, []);
215
219
  logger.error(`Error voting on proposal ${proposalId}: ${errorMsg}`);
@@ -226,9 +230,9 @@ export class GovernanceContract {
226
230
  }
227
231
  logger.info(`Voted [${inFavor ? 'yea' : 'nay'}] on proposal [${proposalId}]`);
228
232
  const proposal = await this.getProposal(proposalId);
229
- logger.info(`Proposal [${proposalId}] has state [${proposal.state}]`);
233
+ logger.info(`Proposal [${proposalId}] has cached state [${proposal.cachedState}]`);
230
234
  logger.info(`Proposal [${proposalId}] has summedBallot yea [${proposal.summedBallot.yea}]`);
231
- logger.info(`Proposal [${proposalId}] has summedBallot nea [${proposal.summedBallot.nea}]`);
235
+ logger.info(`Proposal [${proposalId}] has summedBallot nay [${proposal.summedBallot.nay}]`);
232
236
  }
233
237
 
234
238
  public async executeProposal({
@@ -240,8 +244,7 @@ export class GovernanceContract {
240
244
  retries: number;
241
245
  logger: Logger;
242
246
  }) {
243
- const walletGovernance = this.assertWalletGovernance();
244
- const l1TxUtils = new L1TxUtils(this.publicClient, this.walletClient!, logger);
247
+ const l1TxUtils = createL1TxUtilsFromViemWallet(this.client, { logger });
245
248
  const retryDelaySeconds = 12;
246
249
  let success = false;
247
250
  for (let i = 0; i < retries; i++) {
@@ -254,7 +257,7 @@ export class GovernanceContract {
254
257
  const encodedExecuteData = encodeFunctionData(executeFunctionData);
255
258
 
256
259
  const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
257
- to: walletGovernance.address,
260
+ to: this.governanceContract.address,
258
261
  data: encodedExecuteData,
259
262
  });
260
263
 
@@ -264,7 +267,7 @@ export class GovernanceContract {
264
267
  } else {
265
268
  const args = {
266
269
  ...executeFunctionData,
267
- address: walletGovernance.address,
270
+ address: this.governanceContract.address,
268
271
  };
269
272
  const errorMsg = await l1TxUtils.tryGetErrorFromRevertedTx(encodedExecuteData, args, undefined, []);
270
273
  logger.error(`Error executing proposal ${proposalId}: ${errorMsg}`);