@aztec/ethereum 0.0.1-commit.b655e406 → 0.0.1-commit.b9865e97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/account.d.ts +1 -1
- package/dest/chain.d.ts +1 -1
- package/dest/client.d.ts +25 -3
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +60 -4
- package/dest/config.d.ts +29 -73
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +70 -387
- package/dest/constants.d.ts +1 -1
- package/dest/contracts/chain_state_override.d.ts +78 -0
- package/dest/contracts/chain_state_override.d.ts.map +1 -0
- package/dest/contracts/chain_state_override.js +137 -0
- package/dest/contracts/empire_base.d.ts +7 -5
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/empire_base.js +1 -1
- package/dest/contracts/errors.d.ts +1 -1
- package/dest/contracts/errors.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.d.ts +6 -5
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.js +11 -9
- package/dest/contracts/fee_asset_price_oracle.d.ts +105 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
- package/dest/contracts/fee_asset_price_oracle.js +656 -0
- package/dest/contracts/fee_juice.d.ts +1 -1
- package/dest/contracts/fee_juice.d.ts.map +1 -1
- package/dest/contracts/governance.d.ts +113 -36
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +207 -16
- package/dest/contracts/governance_proposer.d.ts +38 -4
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +455 -12
- package/dest/contracts/gse.d.ts +1 -1
- package/dest/contracts/gse.d.ts.map +1 -1
- package/dest/contracts/inbox.d.ts +24 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +42 -2
- package/dest/contracts/index.d.ts +6 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +5 -2
- package/dest/contracts/log.d.ts +13 -0
- package/dest/contracts/log.d.ts.map +1 -0
- package/dest/contracts/log.js +1 -0
- package/dest/contracts/multicall.d.ts +127 -12
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +201 -93
- package/dest/contracts/outbox.d.ts +64 -0
- package/dest/contracts/outbox.d.ts.map +1 -0
- package/dest/contracts/outbox.js +113 -0
- package/dest/contracts/registry.d.ts +3 -1
- package/dest/contracts/registry.d.ts.map +1 -1
- package/dest/contracts/registry.js +30 -1
- package/dest/contracts/rollup.d.ts +5432 -131
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +1114 -231
- package/dest/contracts/slasher_contract.d.ts +1 -1
- package/dest/contracts/slasher_contract.d.ts.map +1 -1
- package/dest/contracts/{tally_slashing_proposer.d.ts → slashing_proposer.d.ts} +11 -10
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/{tally_slashing_proposer.js → slashing_proposer.js} +21 -16
- package/dest/contracts/utils.d.ts +1 -1
- package/dest/deploy_aztec_l1_contracts.d.ts +257 -0
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
- package/dest/deploy_aztec_l1_contracts.js +410 -0
- package/dest/deploy_l1_contract.d.ts +68 -0
- package/dest/deploy_l1_contract.d.ts.map +1 -0
- package/dest/deploy_l1_contract.js +312 -0
- package/dest/eth-signer/eth-signer.d.ts +1 -1
- package/dest/eth-signer/index.d.ts +1 -1
- package/dest/forwarder_proxy.d.ts +32 -0
- package/dest/forwarder_proxy.d.ts.map +1 -0
- package/dest/forwarder_proxy.js +93 -0
- package/dest/generated/l1-contracts-defaults.d.ts +30 -0
- package/dest/generated/l1-contracts-defaults.d.ts.map +1 -0
- package/dest/generated/l1-contracts-defaults.js +30 -0
- package/dest/l1_artifacts.d.ts +19816 -16730
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +9 -24
- package/dest/l1_contract_addresses.d.ts +61 -65
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +99 -80
- package/dest/l1_reader.d.ts +7 -5
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +15 -7
- package/dest/l1_tx_utils/config.d.ts +11 -5
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +43 -7
- package/dest/l1_tx_utils/constants.d.ts +8 -2
- package/dest/l1_tx_utils/constants.d.ts.map +1 -1
- package/dest/l1_tx_utils/constants.js +27 -2
- package/dest/l1_tx_utils/factory.d.ts +18 -10
- package/dest/l1_tx_utils/factory.d.ts.map +1 -1
- package/dest/l1_tx_utils/factory.js +17 -7
- package/dest/l1_tx_utils/fee-strategies/index.d.ts +10 -0
- package/dest/l1_tx_utils/fee-strategies/index.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/index.js +12 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts +8 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +129 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts +23 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +191 -0
- package/dest/l1_tx_utils/fee-strategies/types.d.ts +51 -0
- package/dest/l1_tx_utils/fee-strategies/types.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/types.js +3 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +41 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +42 -0
- package/dest/l1_tx_utils/index-blobs.d.ts +3 -0
- package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -0
- package/dest/l1_tx_utils/index-blobs.js +2 -0
- package/dest/l1_tx_utils/index.d.ts +4 -1
- package/dest/l1_tx_utils/index.d.ts.map +1 -1
- package/dest/l1_tx_utils/index.js +3 -0
- package/dest/l1_tx_utils/interfaces.d.ts +2 -2
- package/dest/l1_tx_utils/interfaces.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +233 -0
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -0
- package/dest/l1_tx_utils/l1_fee_analyzer.js +506 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +26 -8
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +118 -70
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +19 -30
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +65 -168
- package/dest/l1_tx_utils/signer.d.ts +1 -1
- package/dest/l1_tx_utils/tx_delayer.d.ts +58 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
- package/dest/{test → l1_tx_utils}/tx_delayer.js +70 -39
- package/dest/l1_tx_utils/types.d.ts +1 -1
- package/dest/l1_tx_utils/types.d.ts.map +1 -1
- package/dest/l1_tx_utils/utils.d.ts +1 -1
- package/dest/l1_types.d.ts +1 -1
- package/dest/publisher_manager.d.ts +21 -6
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +81 -7
- package/dest/queries.d.ts +14 -3
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +78 -9
- package/dest/test/chain_monitor.d.ts +48 -25
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +71 -38
- package/dest/test/eth_cheat_codes.d.ts +22 -6
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +28 -7
- package/dest/test/eth_cheat_codes_with_state.d.ts +1 -1
- package/dest/test/eth_cheat_codes_with_state.d.ts.map +1 -1
- package/dest/test/index.d.ts +1 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +0 -2
- package/dest/test/rollup_cheat_codes.d.ts +46 -14
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +118 -42
- package/dest/test/start_anvil.d.ts +25 -2
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +143 -28
- package/dest/test/upgrade_utils.d.ts +1 -1
- package/dest/test/upgrade_utils.js +2 -2
- package/dest/types.d.ts +57 -2
- package/dest/types.d.ts.map +1 -1
- package/dest/utils.d.ts +24 -4
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +112 -16
- package/dest/zkPassportVerifierAddress.d.ts +1 -1
- package/package.json +35 -17
- package/src/client.ts +66 -2
- package/src/config.ts +91 -469
- package/src/contracts/README.md +157 -0
- package/src/contracts/chain_state_override.ts +200 -0
- package/src/contracts/empire_base.ts +6 -5
- package/src/contracts/fee_asset_handler.ts +10 -7
- package/src/contracts/fee_asset_price_oracle.ts +285 -0
- package/src/contracts/governance.ts +279 -13
- package/src/contracts/governance_proposer.ts +74 -7
- package/src/contracts/inbox.ts +64 -4
- package/src/contracts/index.ts +5 -2
- package/src/contracts/log.ts +13 -0
- package/src/contracts/multicall.ts +243 -102
- package/src/contracts/outbox.ts +132 -0
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +819 -192
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +26 -21
- package/src/deploy_aztec_l1_contracts.ts +646 -0
- package/src/deploy_l1_contract.ts +362 -0
- package/src/forwarder_proxy.ts +108 -0
- package/src/generated/l1-contracts-defaults.ts +32 -0
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +120 -92
- package/src/l1_reader.ts +25 -10
- package/src/l1_tx_utils/config.ts +52 -11
- package/src/l1_tx_utils/constants.ts +13 -2
- package/src/l1_tx_utils/factory.ts +31 -31
- package/src/l1_tx_utils/fee-strategies/index.ts +22 -0
- package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +163 -0
- package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +245 -0
- package/src/l1_tx_utils/fee-strategies/types.ts +56 -0
- package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +108 -0
- package/src/l1_tx_utils/index-blobs.ts +2 -0
- package/src/l1_tx_utils/index.ts +3 -0
- package/src/l1_tx_utils/interfaces.ts +1 -1
- package/src/l1_tx_utils/l1_fee_analyzer.ts +803 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +123 -52
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +79 -214
- package/src/{test → l1_tx_utils}/tx_delayer.ts +97 -58
- package/src/publisher_manager.ts +107 -10
- package/src/queries.ts +87 -10
- package/src/test/chain_monitor.ts +115 -51
- package/src/test/eth_cheat_codes.ts +25 -7
- package/src/test/index.ts +0 -2
- package/src/test/rollup_cheat_codes.ts +123 -45
- package/src/test/start_anvil.ts +179 -27
- package/src/test/upgrade_utils.ts +2 -2
- package/src/types.ts +62 -0
- package/src/utils.ts +128 -19
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -65
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -194
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- package/dest/deploy_l1_contracts.d.ts +0 -226
- package/dest/deploy_l1_contracts.d.ts.map +0 -1
- package/dest/deploy_l1_contracts.js +0 -1473
- package/dest/index.d.ts +0 -18
- package/dest/index.d.ts.map +0 -1
- package/dest/index.js +0 -17
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +0 -26
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +0 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +0 -26
- package/dest/test/delayed_tx_utils.d.ts +0 -13
- package/dest/test/delayed_tx_utils.d.ts.map +0 -1
- package/dest/test/delayed_tx_utils.js +0 -28
- package/dest/test/tx_delayer.d.ts +0 -36
- package/dest/test/tx_delayer.d.ts.map +0 -1
- package/src/contracts/empire_slashing_proposer.ts +0 -259
- package/src/deploy_l1_contracts.ts +0 -1849
- package/src/index.ts +0 -17
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
- package/src/test/delayed_tx_utils.ts +0 -52
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { memoize } from '@aztec/foundation/decorators';
|
|
2
3
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
4
|
import { GovernanceProposerAbi } from '@aztec/l1-artifacts/GovernanceProposerAbi';
|
|
@@ -14,11 +15,19 @@ import {
|
|
|
14
15
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
15
16
|
import type { ViemClient } from '../types.js';
|
|
16
17
|
import { type IEmpireBase, encodeSignal, encodeSignalWithSignature, signSignalWithSig } from './empire_base.js';
|
|
17
|
-
import { extractProposalIdFromLogs } from './governance.js';
|
|
18
|
+
import { ReadOnlyGovernanceContract, extractProposalIdFromLogs } from './governance.js';
|
|
18
19
|
|
|
19
20
|
export class GovernanceProposerContract implements IEmpireBase {
|
|
20
21
|
private readonly proposer: GetContractReturnType<typeof GovernanceProposerAbi, ViemClient>;
|
|
21
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Cache of bytecode-existence checks keyed by payload address. The check is stable for a
|
|
25
|
+
* contract's lifetime -- a contract either has code or it does not, and code cannot be removed
|
|
26
|
+
* after deployment (selfdestruct aside, which is not relevant here). Safe to memoize
|
|
27
|
+
* indefinitely for the lifetime of this instance.
|
|
28
|
+
*/
|
|
29
|
+
private readonly emptyPayloadCache: Map<Hex, boolean> = new Map();
|
|
30
|
+
|
|
22
31
|
constructor(
|
|
23
32
|
public readonly client: ViemClient,
|
|
24
33
|
address: Hex | EthAddress,
|
|
@@ -54,15 +63,25 @@ export class GovernanceProposerContract implements IEmpireBase {
|
|
|
54
63
|
return this.proposer.read.getInstance();
|
|
55
64
|
}
|
|
56
65
|
|
|
57
|
-
public computeRound(slot:
|
|
58
|
-
return this.proposer.read.computeRound([slot]);
|
|
66
|
+
public computeRound(slot: SlotNumber): Promise<bigint> {
|
|
67
|
+
return this.proposer.read.computeRound([BigInt(slot)]);
|
|
59
68
|
}
|
|
60
69
|
|
|
61
70
|
public async getRoundInfo(
|
|
62
71
|
rollupAddress: Hex,
|
|
63
72
|
round: bigint,
|
|
64
|
-
): Promise<{ lastSignalSlot:
|
|
65
|
-
|
|
73
|
+
): Promise<{ lastSignalSlot: SlotNumber; payloadWithMostSignals: Hex; quorumReached: boolean; executed: boolean }> {
|
|
74
|
+
const result = await this.proposer.read.getRoundData([rollupAddress, round]);
|
|
75
|
+
const [signalCount, quorum] = await Promise.all([
|
|
76
|
+
this.proposer.read.signalCount([rollupAddress, round, result.payloadWithMostSignals]),
|
|
77
|
+
this.getQuorumSize(),
|
|
78
|
+
]);
|
|
79
|
+
return {
|
|
80
|
+
lastSignalSlot: SlotNumber.fromBigInt(result.lastSignalSlot),
|
|
81
|
+
payloadWithMostSignals: result.payloadWithMostSignals,
|
|
82
|
+
quorumReached: signalCount >= quorum,
|
|
83
|
+
executed: result.executed,
|
|
84
|
+
};
|
|
66
85
|
}
|
|
67
86
|
|
|
68
87
|
public getPayloadSignals(rollupAddress: Hex, round: bigint, payload: Hex): Promise<bigint> {
|
|
@@ -72,13 +91,14 @@ export class GovernanceProposerContract implements IEmpireBase {
|
|
|
72
91
|
public createSignalRequest(payload: Hex): L1TxRequest {
|
|
73
92
|
return {
|
|
74
93
|
to: this.address.toString(),
|
|
94
|
+
abi: GovernanceProposerAbi,
|
|
75
95
|
data: encodeSignal(payload),
|
|
76
96
|
};
|
|
77
97
|
}
|
|
78
98
|
|
|
79
99
|
public async createSignalRequestWithSignature(
|
|
80
100
|
payload: Hex,
|
|
81
|
-
slot:
|
|
101
|
+
slot: SlotNumber,
|
|
82
102
|
chainId: number,
|
|
83
103
|
signerAddress: Hex,
|
|
84
104
|
signer: (msg: TypedDataDefinition) => Promise<Hex>,
|
|
@@ -93,10 +113,56 @@ export class GovernanceProposerContract implements IEmpireBase {
|
|
|
93
113
|
);
|
|
94
114
|
return {
|
|
95
115
|
to: this.address.toString(),
|
|
116
|
+
abi: GovernanceProposerAbi,
|
|
96
117
|
data: encodeSignalWithSignature(payload, signature),
|
|
97
118
|
};
|
|
98
119
|
}
|
|
99
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Resolves the Governance contract this proposer submits winners to. Lazily reads
|
|
123
|
+
* `GovernanceProposer.getGovernance()` (which itself looks the address up via the registry) and
|
|
124
|
+
* memoizes the resulting wrapper.
|
|
125
|
+
*/
|
|
126
|
+
@memoize
|
|
127
|
+
public async getGovernance(): Promise<ReadOnlyGovernanceContract> {
|
|
128
|
+
const address = await this.proposer.read.getGovernance();
|
|
129
|
+
return new ReadOnlyGovernanceContract(address, this.client);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Returns true iff the given original payload is currently the subject of a live (non-terminal)
|
|
134
|
+
* Governance proposal. Delegates to `ReadOnlyGovernanceContract.hasActiveProposalWithPayload`, which
|
|
135
|
+
* implements the actual sweep against the Governance contract -- this method exists only as a
|
|
136
|
+
* convenience wrapper so callers that already hold a GovernanceProposer reference don't have to
|
|
137
|
+
* resolve the Governance address themselves.
|
|
138
|
+
*/
|
|
139
|
+
public async hasActiveProposalWithPayload(payload: Hex): Promise<boolean> {
|
|
140
|
+
const governance = await this.getGovernance();
|
|
141
|
+
return governance.hasActiveProposalWithPayload(payload);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Returns true if the given payload address has no deployed bytecode. Used as a cheap
|
|
146
|
+
* pre-flight check before casting a governance signal — voting for a zero-code address
|
|
147
|
+
* is unrecoverable.
|
|
148
|
+
*
|
|
149
|
+
* We only cache the `false` result (address has bytecode). The `true` result is NOT
|
|
150
|
+
* cached because a CREATE2-redeployed address could go from empty to populated, and
|
|
151
|
+
* caching `true` would make us keep skipping a payload that later becomes valid.
|
|
152
|
+
*/
|
|
153
|
+
public async isPayloadEmpty(payload: EthAddress): Promise<boolean> {
|
|
154
|
+
const key = payload.toString() as Hex;
|
|
155
|
+
if (this.emptyPayloadCache.get(key) === false) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
const code = await this.client.getCode({ address: key });
|
|
159
|
+
const isEmpty = !code || code === '0x';
|
|
160
|
+
if (!isEmpty) {
|
|
161
|
+
this.emptyPayloadCache.set(key, false);
|
|
162
|
+
}
|
|
163
|
+
return isEmpty;
|
|
164
|
+
}
|
|
165
|
+
|
|
100
166
|
public async submitRoundWinner(
|
|
101
167
|
round: bigint,
|
|
102
168
|
l1TxUtils: L1TxUtils,
|
|
@@ -106,8 +172,9 @@ export class GovernanceProposerContract implements IEmpireBase {
|
|
|
106
172
|
}> {
|
|
107
173
|
const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
|
|
108
174
|
to: this.address.toString(),
|
|
175
|
+
abi: GovernanceProposerAbi,
|
|
109
176
|
data: encodeFunctionData({
|
|
110
|
-
abi:
|
|
177
|
+
abi: GovernanceProposerAbi,
|
|
111
178
|
functionName: 'submitRoundWinner',
|
|
112
179
|
args: [round],
|
|
113
180
|
}),
|
package/src/contracts/inbox.ts
CHANGED
|
@@ -1,19 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { maxBigint } from '@aztec/foundation/bigint';
|
|
2
|
+
import { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
4
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
6
|
import { InboxAbi } from '@aztec/l1-artifacts/InboxAbi';
|
|
4
7
|
|
|
5
8
|
import { type BlockTag, type GetContractReturnType, type Hex, getContract } from 'viem';
|
|
6
9
|
|
|
7
10
|
import { getPublicClient } from '../client.js';
|
|
8
|
-
import type {
|
|
11
|
+
import type { DeployAztecL1ContractsReturnType } from '../deploy_aztec_l1_contracts.js';
|
|
9
12
|
import type { L1ReaderConfig } from '../l1_reader.js';
|
|
10
13
|
import type { ViemClient } from '../types.js';
|
|
14
|
+
import type { L1EventLog } from './log.js';
|
|
11
15
|
import { checkBlockTag } from './utils.js';
|
|
12
16
|
|
|
17
|
+
/** Arguments for the MessageSent event. */
|
|
18
|
+
export type MessageSentArgs = {
|
|
19
|
+
index: bigint;
|
|
20
|
+
leaf: Fr;
|
|
21
|
+
checkpointNumber: CheckpointNumber;
|
|
22
|
+
rollingHash: Buffer16;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** Log type for MessageSent events. */
|
|
26
|
+
export type MessageSentLog = L1EventLog<MessageSentArgs>;
|
|
27
|
+
|
|
13
28
|
export class InboxContract {
|
|
14
29
|
private readonly inbox: GetContractReturnType<typeof InboxAbi, ViemClient>;
|
|
15
30
|
|
|
16
|
-
static getFromL1ContractsValues(deployL1ContractsValues:
|
|
31
|
+
static getFromL1ContractsValues(deployL1ContractsValues: DeployAztecL1ContractsReturnType) {
|
|
17
32
|
const {
|
|
18
33
|
l1Client,
|
|
19
34
|
l1ContractAddresses: { inboxAddress },
|
|
@@ -23,7 +38,7 @@ export class InboxContract {
|
|
|
23
38
|
|
|
24
39
|
static getFromConfig(config: L1ReaderConfig) {
|
|
25
40
|
const client = getPublicClient(config);
|
|
26
|
-
const address = config.
|
|
41
|
+
const address = config.inboxAddress.toString();
|
|
27
42
|
return new InboxContract(client, address);
|
|
28
43
|
}
|
|
29
44
|
|
|
@@ -45,6 +60,11 @@ export class InboxContract {
|
|
|
45
60
|
return this.inbox;
|
|
46
61
|
}
|
|
47
62
|
|
|
63
|
+
public async getLag(opts: { blockTag?: BlockTag; blockNumber?: bigint } = {}): Promise<bigint> {
|
|
64
|
+
await checkBlockTag(opts.blockNumber, this.client);
|
|
65
|
+
return await this.inbox.read.LAG(opts);
|
|
66
|
+
}
|
|
67
|
+
|
|
48
68
|
public async getState(opts: { blockTag?: BlockTag; blockNumber?: bigint } = {}): Promise<InboxContractState> {
|
|
49
69
|
await checkBlockTag(opts.blockNumber, this.client);
|
|
50
70
|
const state = await this.inbox.read.getState(opts);
|
|
@@ -54,6 +74,46 @@ export class InboxContract {
|
|
|
54
74
|
treeInProgress: state.inProgress,
|
|
55
75
|
};
|
|
56
76
|
}
|
|
77
|
+
|
|
78
|
+
/** Fetches MessageSent events within the given block range. */
|
|
79
|
+
async getMessageSentEvents(fromBlock: bigint, toBlock: bigint): Promise<MessageSentLog[]> {
|
|
80
|
+
const logs = await this.inbox.getEvents.MessageSent({}, { fromBlock, toBlock });
|
|
81
|
+
return logs
|
|
82
|
+
.filter(log => log.blockNumber! >= fromBlock && log.blockNumber! <= toBlock)
|
|
83
|
+
.map(log => this.mapMessageSentLog(log));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Fetches MessageSent events for a specific message hash around a specific block. */
|
|
87
|
+
async getMessageSentEventByHash(msgHash: Hex, aroundL1BlockNumber: bigint): Promise<MessageSentLog> {
|
|
88
|
+
// We don't use blockHash here because we don't want the query to throw if the L1 block number no longer exists on chain
|
|
89
|
+
// due to an L1 reorg. The use case for this method is usually checking if a message still exists on the Inbox after
|
|
90
|
+
// a reorg, so it's possible the message was moved one block up or down, and that the original L1 block where we
|
|
91
|
+
// saw it no longer exists, rendering the block-by-hash approach invalid.
|
|
92
|
+
const [log] = await this.inbox.getEvents.MessageSent(
|
|
93
|
+
{ hash: msgHash },
|
|
94
|
+
{ fromBlock: maxBigint(aroundL1BlockNumber - 5n, 1n), toBlock: aroundL1BlockNumber + 5n },
|
|
95
|
+
);
|
|
96
|
+
return log && this.mapMessageSentLog(log);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private mapMessageSentLog(log: {
|
|
100
|
+
blockNumber: bigint | null;
|
|
101
|
+
blockHash: `0x${string}` | null;
|
|
102
|
+
transactionHash: `0x${string}` | null;
|
|
103
|
+
args: { index?: bigint; hash?: `0x${string}`; checkpointNumber?: bigint; rollingHash?: `0x${string}` };
|
|
104
|
+
}): MessageSentLog {
|
|
105
|
+
return {
|
|
106
|
+
l1BlockNumber: log.blockNumber!,
|
|
107
|
+
l1BlockHash: Buffer32.fromString(log.blockHash!),
|
|
108
|
+
l1TransactionHash: log.transactionHash!,
|
|
109
|
+
args: {
|
|
110
|
+
index: log.args.index!,
|
|
111
|
+
leaf: Fr.fromString(log.args.hash!),
|
|
112
|
+
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
113
|
+
rollingHash: Buffer16.fromString(log.args.rollingHash!),
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
57
117
|
}
|
|
58
118
|
|
|
59
119
|
export type InboxContractState = {
|
package/src/contracts/index.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
export * from './chain_state_override.js';
|
|
1
2
|
export * from './empire_base.js';
|
|
2
3
|
export * from './errors.js';
|
|
3
4
|
export * from './fee_asset_handler.js';
|
|
5
|
+
export * from './fee_asset_price_oracle.js';
|
|
4
6
|
export * from './fee_juice.js';
|
|
5
7
|
export * from './governance.js';
|
|
6
8
|
export * from './governance_proposer.js';
|
|
7
9
|
export * from './gse.js';
|
|
8
10
|
export * from './inbox.js';
|
|
11
|
+
export * from './log.js';
|
|
9
12
|
export * from './multicall.js';
|
|
13
|
+
export * from './outbox.js';
|
|
10
14
|
export * from './registry.js';
|
|
11
15
|
export * from './rollup.js';
|
|
12
|
-
export * from './
|
|
13
|
-
export * from './tally_slashing_proposer.js';
|
|
16
|
+
export * from './slashing_proposer.js';
|
|
14
17
|
export * from './slasher_contract.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Buffer32 } from '@aztec/foundation/buffer';
|
|
2
|
+
|
|
3
|
+
/** Base L1 event log with common fields. */
|
|
4
|
+
export type L1EventLog<T> = {
|
|
5
|
+
/** L1 block number where the event was emitted. */
|
|
6
|
+
l1BlockNumber: bigint;
|
|
7
|
+
/** L1 block hash. */
|
|
8
|
+
l1BlockHash: Buffer32;
|
|
9
|
+
/** L1 transaction hash that emitted the event. */
|
|
10
|
+
l1TransactionHash: `0x${string}`;
|
|
11
|
+
/** Event-specific arguments. */
|
|
12
|
+
args: T;
|
|
13
|
+
};
|
|
@@ -1,123 +1,264 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { TimeoutError } from '@aztec/foundation/error';
|
|
1
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
2
|
import type { Logger } from '@aztec/foundation/log';
|
|
4
3
|
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
type Abi,
|
|
6
|
+
type Address,
|
|
7
|
+
type BlockOverrides,
|
|
8
|
+
type Hex,
|
|
9
|
+
type RequiredBy,
|
|
10
|
+
type StateOverride,
|
|
11
|
+
type TransactionReceipt,
|
|
12
|
+
decodeFunctionResult,
|
|
13
|
+
encodeFunctionData,
|
|
14
|
+
multicall3Abi,
|
|
15
|
+
} from 'viem';
|
|
6
16
|
|
|
7
17
|
import type { L1BlobInputs, L1TxConfig, L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
8
18
|
import type { ExtendedViemWalletClient } from '../types.js';
|
|
9
|
-
import {
|
|
10
|
-
import { RollupContract } from './rollup.js';
|
|
19
|
+
import { tryDecodeRevertReason } from '../utils.js';
|
|
11
20
|
|
|
12
21
|
export const MULTI_CALL_3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11' as const;
|
|
13
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Thrown by `Multicall3.forward` when the forwarder transaction lands but the receipt reports a
|
|
25
|
+
* reverted status. This is not expected (aggregate3 uses allowFailure: true), so callers should
|
|
26
|
+
* treat it as a fatal on-chain failure rather than retrying on a different publisher.
|
|
27
|
+
*/
|
|
28
|
+
export class MulticallForwarderRevertedError extends Error {
|
|
29
|
+
constructor(public readonly receipt: TransactionReceipt) {
|
|
30
|
+
super(`Multicall3 forwarder tx reverted: ${receipt.transactionHash}`);
|
|
31
|
+
this.name = 'MulticallForwarderRevertedError';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** ABI fragment for aggregate3Value — not included in viem's multicall3Abi. */
|
|
36
|
+
export const aggregate3ValueAbi = [
|
|
37
|
+
{
|
|
38
|
+
inputs: [
|
|
39
|
+
{
|
|
40
|
+
components: [
|
|
41
|
+
{ internalType: 'address', name: 'target', type: 'address' },
|
|
42
|
+
{ internalType: 'bool', name: 'allowFailure', type: 'bool' },
|
|
43
|
+
{ internalType: 'uint256', name: 'value', type: 'uint256' },
|
|
44
|
+
{ internalType: 'bytes', name: 'callData', type: 'bytes' },
|
|
45
|
+
],
|
|
46
|
+
internalType: 'struct Multicall3.Call3Value[]',
|
|
47
|
+
name: 'calls',
|
|
48
|
+
type: 'tuple[]',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
name: 'aggregate3Value',
|
|
52
|
+
outputs: [
|
|
53
|
+
{
|
|
54
|
+
components: [
|
|
55
|
+
{ internalType: 'bool', name: 'success', type: 'bool' },
|
|
56
|
+
{ internalType: 'bytes', name: 'returnData', type: 'bytes' },
|
|
57
|
+
],
|
|
58
|
+
internalType: 'struct Multicall3.Result[]',
|
|
59
|
+
name: 'returnData',
|
|
60
|
+
type: 'tuple[]',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
stateMutability: 'payable',
|
|
64
|
+
type: 'function',
|
|
65
|
+
},
|
|
66
|
+
] as const;
|
|
67
|
+
|
|
68
|
+
/** A single call to embed inside an aggregate3 simulation. The abi is used to decode revert reasons. */
|
|
69
|
+
export type SimulateAggregate3Request = {
|
|
70
|
+
to: Address;
|
|
71
|
+
data: Hex;
|
|
72
|
+
/** Optional ABI used to decode the revert reason if this entry reverts. */
|
|
73
|
+
abi?: Abi;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export type SimulateAggregate3EntryResult = {
|
|
77
|
+
success: boolean;
|
|
78
|
+
/** Decoded revert reason text when `success === false` and a request abi was provided. */
|
|
79
|
+
revertReason?: string;
|
|
80
|
+
/** Raw return data hex. `'0x'` for successful entries with void return. */
|
|
81
|
+
returnData: Hex;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Outcome of a bundle simulation.
|
|
86
|
+
* - `decoded`: eth_simulateV1 ran and produced a per-entry Result[]. Use `entries` for filtering.
|
|
87
|
+
* - `fallback`: the node does not support eth_simulateV1; `fallbackGasEstimate` was returned and no
|
|
88
|
+
* per-entry info is available. Caller should send the bundle as-is with a conservative gas cap.
|
|
89
|
+
*/
|
|
90
|
+
export type SimulateAggregate3Result =
|
|
91
|
+
| { kind: 'decoded'; entries: SimulateAggregate3EntryResult[]; gasUsed: bigint }
|
|
92
|
+
| { kind: 'fallback'; gasUsed: bigint };
|
|
93
|
+
|
|
94
|
+
export type SimulateAggregate3Options = {
|
|
95
|
+
blockOverrides?: BlockOverrides<bigint, number>;
|
|
96
|
+
stateOverrides?: StateOverride;
|
|
97
|
+
/**
|
|
98
|
+
* If set, append a state override that fakes the sender's balance during the simulation so a
|
|
99
|
+
* low or zero balance does not cause the simulate to fail with insufficient funds. The fake
|
|
100
|
+
* balance is applied to `l1TxUtils.getSenderAddress()`.
|
|
101
|
+
*/
|
|
102
|
+
fakeSenderBalance?: bigint;
|
|
103
|
+
/** Gas cap to pass on the simulate call itself (defaults to viem's behavior). */
|
|
104
|
+
gas?: bigint;
|
|
105
|
+
/** When eth_simulateV1 is unavailable, fall back to this gas estimate instead of throwing. */
|
|
106
|
+
fallbackGasEstimate?: bigint;
|
|
107
|
+
};
|
|
108
|
+
|
|
14
109
|
export class Multicall3 {
|
|
15
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Returns true iff Multicall3 bytecode is deployed at MULTI_CALL_3_ADDRESS. An empty result from
|
|
112
|
+
* a non-existent contract would otherwise silently validate any bundle that uses Multicall3.
|
|
113
|
+
*/
|
|
114
|
+
static async hasCode(l1TxUtils: L1TxUtils): Promise<boolean> {
|
|
115
|
+
const code = await l1TxUtils.getCode(EthAddress.fromString(MULTI_CALL_3_ADDRESS));
|
|
116
|
+
return !!code && code !== '0x';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Simulates an aggregate3 call composed of the given requests via eth_simulateV1 and decodes the
|
|
121
|
+
* per-entry Result[]. Entries that revert are returned with a decoded revertReason (if the request
|
|
122
|
+
* provided an abi).
|
|
123
|
+
*
|
|
124
|
+
* Use this to pre-validate a bundle before sending it through `Multicall3.forward`. The caller can
|
|
125
|
+
* drop reverted entries from the bundle and re-simulate with the reduced list to get an accurate
|
|
126
|
+
* `gasUsed`.
|
|
127
|
+
*/
|
|
128
|
+
static async simulateAggregate3(
|
|
129
|
+
requests: SimulateAggregate3Request[],
|
|
130
|
+
l1TxUtils: L1TxUtils,
|
|
131
|
+
opts: SimulateAggregate3Options = {},
|
|
132
|
+
): Promise<SimulateAggregate3Result> {
|
|
133
|
+
const calldata = encodeFunctionData({
|
|
134
|
+
abi: multicall3Abi,
|
|
135
|
+
functionName: 'aggregate3',
|
|
136
|
+
args: [
|
|
137
|
+
requests.map(r => ({
|
|
138
|
+
target: r.to,
|
|
139
|
+
callData: r.data,
|
|
140
|
+
allowFailure: true,
|
|
141
|
+
})),
|
|
142
|
+
],
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const stateOverrides: StateOverride = [...(opts.stateOverrides ?? [])];
|
|
146
|
+
if (opts.fakeSenderBalance !== undefined) {
|
|
147
|
+
stateOverrides.push({
|
|
148
|
+
address: l1TxUtils.getSenderAddress().toString(),
|
|
149
|
+
balance: opts.fakeSenderBalance,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const simResult = await l1TxUtils.simulate(
|
|
154
|
+
{ to: MULTI_CALL_3_ADDRESS, data: calldata, gas: opts.gas },
|
|
155
|
+
opts.blockOverrides,
|
|
156
|
+
stateOverrides,
|
|
157
|
+
multicall3Abi,
|
|
158
|
+
{ fallbackGasEstimate: opts.fallbackGasEstimate },
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
if (simResult.result === '0x') {
|
|
162
|
+
return { kind: 'fallback', gasUsed: simResult.gasUsed };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const decoded = decodeFunctionResult({
|
|
166
|
+
abi: multicall3Abi,
|
|
167
|
+
functionName: 'aggregate3',
|
|
168
|
+
data: simResult.result,
|
|
169
|
+
}) as readonly { success: boolean; returnData: `0x${string}` }[];
|
|
170
|
+
|
|
171
|
+
const entries: SimulateAggregate3EntryResult[] = decoded.map((entry, i) => {
|
|
172
|
+
if (entry.success) {
|
|
173
|
+
return { success: true, returnData: entry.returnData };
|
|
174
|
+
}
|
|
175
|
+
const abi = requests[i].abi;
|
|
176
|
+
const revertReason = abi ? tryDecodeRevertReason(entry.returnData, abi) : undefined;
|
|
177
|
+
return { success: false, returnData: entry.returnData, revertReason };
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
return { kind: 'decoded', entries, gasUsed: simResult.gasUsed };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Sends a batch of requests through aggregate3. Individual calls may fail (allowFailure: true),
|
|
185
|
+
* but the top-level multicall is expected to land successfully. Throws if the send fails or if
|
|
186
|
+
* the receipt reports a reverted status.
|
|
187
|
+
*/
|
|
188
|
+
static async forward<TOptGasLimitRequired extends boolean>(
|
|
16
189
|
requests: L1TxRequest[],
|
|
17
190
|
l1TxUtils: L1TxUtils,
|
|
18
|
-
gasConfig: L1TxConfig | undefined,
|
|
191
|
+
gasConfig: TOptGasLimitRequired extends true ? RequiredBy<L1TxConfig, 'gasLimit'> : L1TxConfig | undefined,
|
|
19
192
|
blobConfig: L1BlobInputs | undefined,
|
|
20
|
-
|
|
21
|
-
logger: Logger,
|
|
22
|
-
opts: { revertOnFailure?: boolean } = {},
|
|
193
|
+
opts: { gasLimitRequired?: TOptGasLimitRequired } = {},
|
|
23
194
|
) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
195
|
+
if (opts.gasLimitRequired && !gasConfig?.gasLimit) {
|
|
196
|
+
throw new Error('Multicall gasLimit is required when gasLimitRequired is true');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const args = requests
|
|
200
|
+
.filter(request => request.to !== null)
|
|
201
|
+
.map(r => ({
|
|
202
|
+
target: r.to!,
|
|
203
|
+
callData: r.data!,
|
|
204
|
+
allowFailure: true,
|
|
205
|
+
}));
|
|
206
|
+
const encodedForwarderData = encodeFunctionData({
|
|
31
207
|
abi: multicall3Abi,
|
|
32
208
|
functionName: 'aggregate3',
|
|
33
209
|
args: [args],
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const encodedForwarderData = encodeFunctionData(forwarderFunctionData);
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
const { receipt, state } = await l1TxUtils.sendAndMonitorTransaction(
|
|
40
|
-
{ to: MULTI_CALL_3_ADDRESS, data: encodedForwarderData },
|
|
41
|
-
gasConfig,
|
|
42
|
-
blobConfig,
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
if (receipt.status === 'success') {
|
|
46
|
-
const stats = await l1TxUtils.getTransactionStats(receipt.transactionHash);
|
|
47
|
-
return { receipt, stats };
|
|
48
|
-
} else {
|
|
49
|
-
logger.error('Forwarder transaction failed', undefined, { receipt });
|
|
50
|
-
|
|
51
|
-
const args = {
|
|
52
|
-
...forwarderFunctionData,
|
|
53
|
-
address: MULTI_CALL_3_ADDRESS,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
let errorMsg: string | undefined;
|
|
57
|
-
|
|
58
|
-
if (blobConfig) {
|
|
59
|
-
const maxFeePerBlobGas = blobConfig.maxFeePerBlobGas ?? state.gasPrice.maxFeePerBlobGas;
|
|
60
|
-
if (maxFeePerBlobGas === undefined) {
|
|
61
|
-
errorMsg = 'maxFeePerBlobGas is required to get the error message';
|
|
62
|
-
} else {
|
|
63
|
-
logger.debug('Trying to get error from reverted tx with blob config');
|
|
64
|
-
errorMsg = await l1TxUtils.tryGetErrorFromRevertedTx(
|
|
65
|
-
encodedForwarderData,
|
|
66
|
-
args,
|
|
67
|
-
{
|
|
68
|
-
blobs: blobConfig.blobs,
|
|
69
|
-
kzg: blobConfig.kzg,
|
|
70
|
-
maxFeePerBlobGas,
|
|
71
|
-
},
|
|
72
|
-
[
|
|
73
|
-
{
|
|
74
|
-
address: rollupAddress,
|
|
75
|
-
stateDiff: [
|
|
76
|
-
{
|
|
77
|
-
slot: toPaddedHex(RollupContract.checkBlobStorageSlot, true),
|
|
78
|
-
value: toPaddedHex(0n, true),
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
} else {
|
|
86
|
-
logger.debug('Trying to get error from reverted tx without blob config');
|
|
87
|
-
errorMsg = await l1TxUtils.tryGetErrorFromRevertedTx(encodedForwarderData, args, undefined, []);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return { receipt, errorMsg };
|
|
91
|
-
}
|
|
92
|
-
} catch (err) {
|
|
93
|
-
if (err instanceof TimeoutError) {
|
|
94
|
-
throw err;
|
|
95
|
-
}
|
|
210
|
+
});
|
|
96
211
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
data: request.data,
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
return result;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
logger.warn('Failed to get error from reverted tx', { err });
|
|
119
|
-
throw err;
|
|
212
|
+
const { receipt } = await l1TxUtils.sendAndMonitorTransaction(
|
|
213
|
+
{
|
|
214
|
+
to: MULTI_CALL_3_ADDRESS,
|
|
215
|
+
data: encodedForwarderData,
|
|
216
|
+
abi: multicall3Abi,
|
|
217
|
+
},
|
|
218
|
+
gasConfig,
|
|
219
|
+
blobConfig,
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
// This shouldn't happen. Any failure in individual calls is swallowed by forward since we set
|
|
223
|
+
// allowFailure to true for all calls, so a reverted status here would indicate a problem with
|
|
224
|
+
// the Multicall3 contract itself or the forwarder transaction (such as an out-of-gas).
|
|
225
|
+
if (receipt.status !== 'success') {
|
|
226
|
+
throw new MulticallForwarderRevertedError(receipt);
|
|
120
227
|
}
|
|
228
|
+
|
|
229
|
+
const stats = await l1TxUtils.getTransactionStats(receipt.transactionHash);
|
|
230
|
+
return { receipt, stats, multicallData: encodedForwarderData };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Batch multiple value transfers into a single aggregate3Value call on Multicall3. */
|
|
234
|
+
static async forwardValue(calls: { to: Address; value: bigint }[], l1TxUtils: L1TxUtils, logger: Logger) {
|
|
235
|
+
const args = calls.map(c => ({
|
|
236
|
+
target: c.to,
|
|
237
|
+
allowFailure: false,
|
|
238
|
+
value: c.value,
|
|
239
|
+
callData: '0x' as Hex,
|
|
240
|
+
}));
|
|
241
|
+
|
|
242
|
+
const data = encodeFunctionData({
|
|
243
|
+
abi: aggregate3ValueAbi,
|
|
244
|
+
functionName: 'aggregate3Value',
|
|
245
|
+
args: [args],
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const totalValue = calls.reduce((sum, c) => sum + c.value, 0n);
|
|
249
|
+
|
|
250
|
+
logger.info(`Sending aggregate3Value with ${calls.length} calls`, { totalValue });
|
|
251
|
+
const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
|
|
252
|
+
to: MULTI_CALL_3_ADDRESS,
|
|
253
|
+
data,
|
|
254
|
+
value: totalValue,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
if (receipt.status !== 'success') {
|
|
258
|
+
throw new Error(`aggregate3Value transaction reverted: ${receipt.transactionHash}`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return { receipt };
|
|
121
262
|
}
|
|
122
263
|
}
|
|
123
264
|
|