@aztec/ethereum 0.73.0 → 0.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/contracts/empire_base.d.ts +13 -0
- package/dest/contracts/empire_base.d.ts.map +1 -0
- package/dest/contracts/empire_base.js +10 -0
- package/dest/contracts/forwarder.d.ts +4 -3
- package/dest/contracts/forwarder.d.ts.map +1 -1
- package/dest/contracts/forwarder.js +29 -14
- package/dest/contracts/governance_proposer.d.ts +19 -4
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +33 -2
- package/dest/contracts/index.d.ts +2 -1
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +3 -2
- package/dest/contracts/rollup.d.ts +2 -0
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +19 -9
- package/dest/contracts/slashing_proposer.d.ts +14 -4
- package/dest/contracts/slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/slashing_proposer.js +19 -1
- package/dest/deploy_l1_contracts.d.ts +1448 -203
- package/dest/deploy_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_l1_contracts.js +6 -2
- package/dest/l1_tx_utils.d.ts +7 -6
- package/dest/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils.js +6 -17
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +25 -4
- package/package.json +3 -3
- package/src/contracts/empire_base.ts +19 -0
- package/src/contracts/forwarder.ts +37 -14
- package/src/contracts/governance_proposer.ts +54 -4
- package/src/contracts/index.ts +2 -1
- package/src/contracts/rollup.ts +20 -8
- package/src/contracts/slashing_proposer.ts +29 -2
- package/src/deploy_l1_contracts.ts +6 -0
- package/src/l1_tx_utils.ts +9 -19
- package/src/utils.ts +29 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EmpireBaseAbi } from '@aztec/l1-artifacts/EmpireBaseAbi';
|
|
2
|
+
|
|
3
|
+
import { type Hex, encodeFunctionData } from 'viem';
|
|
4
|
+
|
|
5
|
+
import { type L1TxRequest } from '../l1_tx_utils.js';
|
|
6
|
+
|
|
7
|
+
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
|
+
}
|
|
12
|
+
|
|
13
|
+
export function encodeVote(payload: Hex): Hex {
|
|
14
|
+
return encodeFunctionData({
|
|
15
|
+
abi: EmpireBaseAbi,
|
|
16
|
+
functionName: 'vote',
|
|
17
|
+
args: [payload],
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { toHex } from '@aztec/foundation/bigint-buffer';
|
|
1
2
|
import { type Logger } from '@aztec/foundation/log';
|
|
2
3
|
import { ForwarderAbi, ForwarderBytecode } from '@aztec/l1-artifacts';
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
type Account,
|
|
6
7
|
type Chain,
|
|
8
|
+
type EncodeFunctionDataParameters,
|
|
7
9
|
type GetContractReturnType,
|
|
8
10
|
type Hex,
|
|
9
11
|
type HttpTransport,
|
|
@@ -15,11 +17,12 @@ import {
|
|
|
15
17
|
|
|
16
18
|
import { type L1Clients, deployL1Contract } from '../deploy_l1_contracts.js';
|
|
17
19
|
import { type L1BlobInputs, type L1GasConfig, type L1TxRequest, type L1TxUtils } from '../l1_tx_utils.js';
|
|
20
|
+
import { RollupContract } from './rollup.js';
|
|
18
21
|
|
|
19
22
|
export class ForwarderContract {
|
|
20
23
|
private readonly forwarder: GetContractReturnType<typeof ForwarderAbi, PublicClient<HttpTransport, Chain>>;
|
|
21
24
|
|
|
22
|
-
constructor(public readonly client: L1Clients['publicClient'], address: Hex) {
|
|
25
|
+
constructor(public readonly client: L1Clients['publicClient'], address: Hex, public readonly rollupAddress: Hex) {
|
|
23
26
|
this.forwarder = getContract({ address, abi: ForwarderAbi, client });
|
|
24
27
|
}
|
|
25
28
|
|
|
@@ -28,6 +31,7 @@ export class ForwarderContract {
|
|
|
28
31
|
walletClient: WalletClient<HttpTransport, Chain, Account>,
|
|
29
32
|
publicClient: PublicClient<HttpTransport, Chain>,
|
|
30
33
|
logger: Logger,
|
|
34
|
+
rollupAddress: Hex,
|
|
31
35
|
) {
|
|
32
36
|
logger.info('Deploying forwarder contract');
|
|
33
37
|
|
|
@@ -48,7 +52,7 @@ export class ForwarderContract {
|
|
|
48
52
|
|
|
49
53
|
logger.info(`Forwarder contract deployed at ${address} with owner ${owner}`);
|
|
50
54
|
|
|
51
|
-
return new ForwarderContract(publicClient, address.toString());
|
|
55
|
+
return new ForwarderContract(publicClient, address.toString(), rollupAddress);
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
public getAddress() {
|
|
@@ -60,20 +64,22 @@ export class ForwarderContract {
|
|
|
60
64
|
l1TxUtils: L1TxUtils,
|
|
61
65
|
gasConfig: L1GasConfig | undefined,
|
|
62
66
|
blobConfig: L1BlobInputs | undefined,
|
|
67
|
+
logger: Logger,
|
|
63
68
|
) {
|
|
64
69
|
requests = requests.filter(request => request.to !== null);
|
|
65
70
|
const toArgs = requests.map(request => request.to!);
|
|
66
71
|
const dataArgs = requests.map(request => request.data!);
|
|
67
|
-
const
|
|
72
|
+
const forwarderFunctionData: EncodeFunctionDataParameters<typeof ForwarderAbi, 'forward'> = {
|
|
68
73
|
abi: ForwarderAbi,
|
|
69
74
|
functionName: 'forward',
|
|
70
75
|
args: [toArgs, dataArgs],
|
|
71
|
-
}
|
|
76
|
+
};
|
|
77
|
+
const encodedForwarderData = encodeFunctionData(forwarderFunctionData);
|
|
72
78
|
|
|
73
79
|
const { receipt, gasPrice } = await l1TxUtils.sendAndMonitorTransaction(
|
|
74
80
|
{
|
|
75
81
|
to: this.forwarder.address,
|
|
76
|
-
data,
|
|
82
|
+
data: encodedForwarderData,
|
|
77
83
|
},
|
|
78
84
|
gasConfig,
|
|
79
85
|
blobConfig,
|
|
@@ -83,10 +89,10 @@ export class ForwarderContract {
|
|
|
83
89
|
const stats = await l1TxUtils.getTransactionStats(receipt.transactionHash);
|
|
84
90
|
return { receipt, gasPrice, stats };
|
|
85
91
|
} else {
|
|
92
|
+
logger.error('Forwarder transaction failed', undefined, { receipt });
|
|
93
|
+
|
|
86
94
|
const args = {
|
|
87
|
-
|
|
88
|
-
functionName: 'forward',
|
|
89
|
-
abi: ForwarderAbi,
|
|
95
|
+
...forwarderFunctionData,
|
|
90
96
|
address: this.forwarder.address,
|
|
91
97
|
};
|
|
92
98
|
|
|
@@ -97,14 +103,31 @@ export class ForwarderContract {
|
|
|
97
103
|
if (maxFeePerBlobGas === undefined) {
|
|
98
104
|
errorMsg = 'maxFeePerBlobGas is required to get the error message';
|
|
99
105
|
} else {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
106
|
+
logger.debug('Trying to get error from reverted tx with blob config');
|
|
107
|
+
errorMsg = await l1TxUtils.tryGetErrorFromRevertedTx(
|
|
108
|
+
encodedForwarderData,
|
|
109
|
+
args,
|
|
110
|
+
{
|
|
111
|
+
blobs: blobConfig.blobs,
|
|
112
|
+
kzg: blobConfig.kzg,
|
|
113
|
+
maxFeePerBlobGas,
|
|
114
|
+
},
|
|
115
|
+
[
|
|
116
|
+
{
|
|
117
|
+
address: this.rollupAddress,
|
|
118
|
+
stateDiff: [
|
|
119
|
+
{
|
|
120
|
+
slot: toHex(RollupContract.checkBlobStorageSlot, true),
|
|
121
|
+
value: toHex(0n, true),
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
);
|
|
105
127
|
}
|
|
106
128
|
} else {
|
|
107
|
-
|
|
129
|
+
logger.debug('Trying to get error from reverted tx without blob config');
|
|
130
|
+
errorMsg = await l1TxUtils.tryGetErrorFromRevertedTx(encodedForwarderData, args, undefined, []);
|
|
108
131
|
}
|
|
109
132
|
|
|
110
133
|
return { receipt, gasPrice, errorMsg };
|
|
@@ -8,13 +8,19 @@ import {
|
|
|
8
8
|
type Hex,
|
|
9
9
|
type HttpTransport,
|
|
10
10
|
type PublicClient,
|
|
11
|
+
type TransactionReceipt,
|
|
12
|
+
encodeFunctionData,
|
|
11
13
|
getContract,
|
|
12
14
|
} from 'viem';
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
import type { L1Clients } from '../deploy_l1_contracts.js';
|
|
17
|
+
import type { GasPrice, L1TxRequest, L1TxUtils } from '../l1_tx_utils.js';
|
|
18
|
+
import { type IEmpireBase, encodeVote } from './empire_base.js';
|
|
19
|
+
|
|
20
|
+
export class GovernanceProposerContract implements IEmpireBase {
|
|
15
21
|
private readonly proposer: GetContractReturnType<typeof GovernanceProposerAbi, PublicClient<HttpTransport, Chain>>;
|
|
16
22
|
|
|
17
|
-
constructor(public readonly client:
|
|
23
|
+
constructor(public readonly client: L1Clients['publicClient'], address: Hex) {
|
|
18
24
|
this.proposer = getContract({ address, abi: GovernanceProposerAbi, client });
|
|
19
25
|
}
|
|
20
26
|
|
|
@@ -31,11 +37,55 @@ export class GovernanceProposerContract {
|
|
|
31
37
|
return EthAddress.fromString(await this.proposer.read.REGISTRY());
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
public getQuorumSize() {
|
|
40
|
+
public getQuorumSize(): Promise<bigint> {
|
|
35
41
|
return this.proposer.read.N();
|
|
36
42
|
}
|
|
37
43
|
|
|
38
|
-
public getRoundSize() {
|
|
44
|
+
public getRoundSize(): Promise<bigint> {
|
|
39
45
|
return this.proposer.read.M();
|
|
40
46
|
}
|
|
47
|
+
|
|
48
|
+
public computeRound(slot: bigint): Promise<bigint> {
|
|
49
|
+
return this.proposer.read.computeRound([slot]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public async getRoundInfo(
|
|
53
|
+
rollupAddress: Hex,
|
|
54
|
+
round: bigint,
|
|
55
|
+
): Promise<{ lastVote: bigint; leader: Hex; executed: boolean }> {
|
|
56
|
+
const roundInfo = await this.proposer.read.rounds([rollupAddress, round]);
|
|
57
|
+
return {
|
|
58
|
+
lastVote: roundInfo[0],
|
|
59
|
+
leader: roundInfo[1],
|
|
60
|
+
executed: roundInfo[2],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public getProposalVotes(rollupAddress: Hex, round: bigint, proposal: Hex): Promise<bigint> {
|
|
65
|
+
return this.proposer.read.yeaCount([rollupAddress, round, proposal]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public createVoteRequest(payload: Hex): L1TxRequest {
|
|
69
|
+
return {
|
|
70
|
+
to: this.address.toString(),
|
|
71
|
+
data: encodeVote(payload),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public executeProposal(
|
|
76
|
+
round: bigint,
|
|
77
|
+
l1TxUtils: L1TxUtils,
|
|
78
|
+
): Promise<{
|
|
79
|
+
receipt: TransactionReceipt;
|
|
80
|
+
gasPrice: GasPrice;
|
|
81
|
+
}> {
|
|
82
|
+
return l1TxUtils.sendAndMonitorTransaction({
|
|
83
|
+
to: this.address.toString(),
|
|
84
|
+
data: encodeFunctionData({
|
|
85
|
+
abi: this.proposer.abi,
|
|
86
|
+
functionName: 'executeProposal',
|
|
87
|
+
args: [round],
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
41
91
|
}
|
package/src/contracts/index.ts
CHANGED
package/src/contracts/rollup.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { memoize } from '@aztec/foundation/decorators';
|
|
2
2
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
3
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
4
|
-
import { RollupAbi, SlasherAbi } from '@aztec/l1-artifacts';
|
|
4
|
+
import { RollupAbi, RollupStorage, SlasherAbi } from '@aztec/l1-artifacts';
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
type Account,
|
|
@@ -45,6 +45,14 @@ export type EpochProofQuoteViemArgs = {
|
|
|
45
45
|
export class RollupContract {
|
|
46
46
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, PublicClient<HttpTransport, Chain>>;
|
|
47
47
|
|
|
48
|
+
static get checkBlobStorageSlot(): bigint {
|
|
49
|
+
const asString = RollupStorage.find(storage => storage.label === 'checkBlob')?.slot;
|
|
50
|
+
if (asString === undefined) {
|
|
51
|
+
throw new Error('checkBlobStorageSlot not found');
|
|
52
|
+
}
|
|
53
|
+
return BigInt(asString);
|
|
54
|
+
}
|
|
55
|
+
|
|
48
56
|
static getFromL1ContractsValues(deployL1ContractsValues: DeployL1Contracts) {
|
|
49
57
|
const {
|
|
50
58
|
publicClient,
|
|
@@ -72,7 +80,7 @@ export class RollupContract {
|
|
|
72
80
|
|
|
73
81
|
@memoize
|
|
74
82
|
public async getSlashingProposer() {
|
|
75
|
-
const slasherAddress = await this.rollup.read.
|
|
83
|
+
const slasherAddress = await this.rollup.read.getSlasher();
|
|
76
84
|
const slasher = getContract({ address: slasherAddress, abi: SlasherAbi, client: this.client });
|
|
77
85
|
const proposerAddress = await slasher.read.PROPOSER();
|
|
78
86
|
return new SlashingProposerContract(this.client, proposerAddress);
|
|
@@ -85,7 +93,7 @@ export class RollupContract {
|
|
|
85
93
|
|
|
86
94
|
@memoize
|
|
87
95
|
getL1GenesisTime() {
|
|
88
|
-
return this.rollup.read.
|
|
96
|
+
return this.rollup.read.getGenesisTime();
|
|
89
97
|
}
|
|
90
98
|
|
|
91
99
|
@memoize
|
|
@@ -95,12 +103,12 @@ export class RollupContract {
|
|
|
95
103
|
|
|
96
104
|
@memoize
|
|
97
105
|
getEpochDuration() {
|
|
98
|
-
return this.rollup.read.
|
|
106
|
+
return this.rollup.read.getEpochDuration();
|
|
99
107
|
}
|
|
100
108
|
|
|
101
109
|
@memoize
|
|
102
110
|
getSlotDuration() {
|
|
103
|
-
return this.rollup.read.
|
|
111
|
+
return this.rollup.read.getSlotDuration();
|
|
104
112
|
}
|
|
105
113
|
|
|
106
114
|
@memoize
|
|
@@ -110,11 +118,11 @@ export class RollupContract {
|
|
|
110
118
|
|
|
111
119
|
@memoize
|
|
112
120
|
getMinimumStake() {
|
|
113
|
-
return this.rollup.read.
|
|
121
|
+
return this.rollup.read.getMinimumStake();
|
|
114
122
|
}
|
|
115
123
|
|
|
116
124
|
public async getSlashingProposerAddress() {
|
|
117
|
-
const slasherAddress = await this.rollup.read.
|
|
125
|
+
const slasherAddress = await this.rollup.read.getSlasher();
|
|
118
126
|
const slasher = getContract({
|
|
119
127
|
address: getAddress(slasherAddress.toString()),
|
|
120
128
|
abi: SlasherAbi,
|
|
@@ -171,6 +179,10 @@ export class RollupContract {
|
|
|
171
179
|
return this.rollup.read.getTips();
|
|
172
180
|
}
|
|
173
181
|
|
|
182
|
+
getTimestampForSlot(slot: bigint) {
|
|
183
|
+
return this.rollup.read.getTimestampForSlot([slot]);
|
|
184
|
+
}
|
|
185
|
+
|
|
174
186
|
async getEpochNumber(blockNumber?: bigint) {
|
|
175
187
|
blockNumber ??= await this.getBlockNumber();
|
|
176
188
|
return this.rollup.read.getEpochForBlock([BigInt(blockNumber)]);
|
|
@@ -191,7 +203,7 @@ export class RollupContract {
|
|
|
191
203
|
this.rollup.read.FEE_JUICE_PORTAL(),
|
|
192
204
|
this.rollup.read.REWARD_DISTRIBUTOR(),
|
|
193
205
|
this.rollup.read.ASSET(),
|
|
194
|
-
this.rollup.read.
|
|
206
|
+
this.rollup.read.getStakingAsset(),
|
|
195
207
|
] as const)
|
|
196
208
|
).map(EthAddress.fromString);
|
|
197
209
|
|
|
@@ -10,10 +10,14 @@ import {
|
|
|
10
10
|
getContract,
|
|
11
11
|
} from 'viem';
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
import type { L1Clients } from '../deploy_l1_contracts.js';
|
|
14
|
+
import type { L1TxRequest } from '../l1_tx_utils.js';
|
|
15
|
+
import { type IEmpireBase, encodeVote } from './empire_base.js';
|
|
16
|
+
|
|
17
|
+
export class SlashingProposerContract implements IEmpireBase {
|
|
14
18
|
private readonly proposer: GetContractReturnType<typeof SlashingProposerAbi, PublicClient<HttpTransport, Chain>>;
|
|
15
19
|
|
|
16
|
-
constructor(public readonly client:
|
|
20
|
+
constructor(public readonly client: L1Clients['publicClient'], address: Hex) {
|
|
17
21
|
this.proposer = getContract({ address, abi: SlashingProposerAbi, client });
|
|
18
22
|
}
|
|
19
23
|
|
|
@@ -28,4 +32,27 @@ export class SlashingProposerContract {
|
|
|
28
32
|
public getRoundSize() {
|
|
29
33
|
return this.proposer.read.M();
|
|
30
34
|
}
|
|
35
|
+
|
|
36
|
+
public computeRound(slot: bigint): Promise<bigint> {
|
|
37
|
+
return this.proposer.read.computeRound([slot]);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public async getRoundInfo(
|
|
41
|
+
rollupAddress: Hex,
|
|
42
|
+
round: bigint,
|
|
43
|
+
): Promise<{ lastVote: bigint; leader: Hex; executed: boolean }> {
|
|
44
|
+
const roundInfo = await this.proposer.read.rounds([rollupAddress, round]);
|
|
45
|
+
return {
|
|
46
|
+
lastVote: roundInfo[0],
|
|
47
|
+
leader: roundInfo[1],
|
|
48
|
+
executed: roundInfo[2],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public createVoteRequest(payload: Hex): L1TxRequest {
|
|
53
|
+
return {
|
|
54
|
+
to: this.address.toString(),
|
|
55
|
+
data: encodeVote(payload),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
31
58
|
}
|
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
RollupLinkReferences,
|
|
29
29
|
SlashFactoryAbi,
|
|
30
30
|
SlashFactoryBytecode,
|
|
31
|
+
StakingLibAbi,
|
|
32
|
+
StakingLibBytecode,
|
|
31
33
|
TestERC20Abi,
|
|
32
34
|
TestERC20Bytecode,
|
|
33
35
|
ValidatorSelectionLibAbi,
|
|
@@ -146,6 +148,10 @@ export const l1Artifacts = {
|
|
|
146
148
|
contractAbi: ExtRollupLibAbi,
|
|
147
149
|
contractBytecode: ExtRollupLibBytecode as Hex,
|
|
148
150
|
},
|
|
151
|
+
StakingLib: {
|
|
152
|
+
contractAbi: StakingLibAbi,
|
|
153
|
+
contractBytecode: StakingLibBytecode as Hex,
|
|
154
|
+
},
|
|
149
155
|
},
|
|
150
156
|
},
|
|
151
157
|
},
|
package/src/l1_tx_utils.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { toHex } from '@aztec/foundation/bigint-buffer';
|
|
2
1
|
import { compactArray, times } from '@aztec/foundation/collection';
|
|
3
2
|
import {
|
|
4
3
|
type ConfigMappingsType,
|
|
@@ -23,7 +22,6 @@ import {
|
|
|
23
22
|
type HttpTransport,
|
|
24
23
|
MethodNotFoundRpcError,
|
|
25
24
|
MethodNotSupportedRpcError,
|
|
26
|
-
type PublicClient,
|
|
27
25
|
type StateOverride,
|
|
28
26
|
type TransactionReceipt,
|
|
29
27
|
type WalletClient,
|
|
@@ -32,6 +30,7 @@ import {
|
|
|
32
30
|
hexToBytes,
|
|
33
31
|
} from 'viem';
|
|
34
32
|
|
|
33
|
+
import { type L1Clients } from './deploy_l1_contracts.js';
|
|
35
34
|
import { formatViemError } from './utils.js';
|
|
36
35
|
|
|
37
36
|
// 1_000_000_000 Gwei = 1 ETH
|
|
@@ -207,7 +206,7 @@ export class L1TxUtils {
|
|
|
207
206
|
private interrupted = false;
|
|
208
207
|
|
|
209
208
|
constructor(
|
|
210
|
-
public publicClient:
|
|
209
|
+
public publicClient: L1Clients['publicClient'],
|
|
211
210
|
public walletClient: WalletClient<HttpTransport, Chain, Account>,
|
|
212
211
|
protected readonly logger?: Logger,
|
|
213
212
|
config?: Partial<L1TxUtilsConfig>,
|
|
@@ -658,32 +657,21 @@ export class L1TxUtils {
|
|
|
658
657
|
public async tryGetErrorFromRevertedTx(
|
|
659
658
|
data: Hex,
|
|
660
659
|
args: {
|
|
661
|
-
args: any[];
|
|
660
|
+
args: readonly any[];
|
|
662
661
|
functionName: string;
|
|
663
662
|
abi: Abi;
|
|
664
663
|
address: Hex;
|
|
665
664
|
},
|
|
666
|
-
blobInputs
|
|
665
|
+
blobInputs: (L1BlobInputs & { maxFeePerBlobGas: bigint }) | undefined,
|
|
666
|
+
stateOverride: StateOverride = [],
|
|
667
667
|
) {
|
|
668
668
|
try {
|
|
669
|
-
// NB: If this fn starts unexpectedly giving incorrect blob hash errors, it may be because the checkBlob
|
|
670
|
-
// bool is no longer at the slot below. To find the slot, run: forge inspect src/core/Rollup.sol:Rollup storage
|
|
671
|
-
const checkBlobSlot = 9n;
|
|
672
669
|
await this.publicClient.simulateContract({
|
|
673
670
|
...args,
|
|
674
671
|
account: this.walletClient.account,
|
|
675
|
-
stateOverride
|
|
676
|
-
{
|
|
677
|
-
address: args.address,
|
|
678
|
-
stateDiff: [
|
|
679
|
-
{
|
|
680
|
-
slot: toHex(checkBlobSlot, true),
|
|
681
|
-
value: toHex(0n, true),
|
|
682
|
-
},
|
|
683
|
-
],
|
|
684
|
-
},
|
|
685
|
-
],
|
|
672
|
+
stateOverride,
|
|
686
673
|
});
|
|
674
|
+
this.logger?.trace('Simulated blob tx', { blobInputs });
|
|
687
675
|
// If the above passes, we have a blob error. We cannot simulate blob txs, and failed txs no longer throw errors.
|
|
688
676
|
// Strangely, the only way to throw the revert reason as an error and provide blobs is prepareTransactionRequest.
|
|
689
677
|
// See: https://github.com/wevm/viem/issues/2075
|
|
@@ -702,7 +690,9 @@ export class L1TxUtils {
|
|
|
702
690
|
to: args.address,
|
|
703
691
|
data,
|
|
704
692
|
};
|
|
693
|
+
this.logger?.trace('Preparing tx', { request });
|
|
705
694
|
await this.walletClient.prepareTransactionRequest(request);
|
|
695
|
+
this.logger?.trace('Prepared tx');
|
|
706
696
|
return undefined;
|
|
707
697
|
} catch (simulationErr: any) {
|
|
708
698
|
// If we don't have a ContractFunctionExecutionError, we have a blob related error => use getContractError to get the error msg.
|
package/src/utils.ts
CHANGED
|
@@ -92,6 +92,30 @@ export function prettyLogViemErrorMsg(err: any) {
|
|
|
92
92
|
return err?.message ?? err;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
function getNestedErrorData(error: unknown): string | undefined {
|
|
96
|
+
// If nothing, bail
|
|
97
|
+
if (!error) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// If it's an object with a `data` property, return it
|
|
102
|
+
// (Remember to check TS type-safely or cast as needed)
|
|
103
|
+
if (typeof error === 'object' && error !== null && 'data' in error) {
|
|
104
|
+
const possibleData = (error as any).data;
|
|
105
|
+
if (typeof possibleData === 'string' && possibleData.startsWith('0x')) {
|
|
106
|
+
return possibleData;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// If it has a `cause`, recurse
|
|
111
|
+
if (typeof error === 'object' && error !== null && 'cause' in error) {
|
|
112
|
+
return getNestedErrorData((error as any).cause);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Not found
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
95
119
|
/**
|
|
96
120
|
* Formats a Viem error into a FormattedViemError instance.
|
|
97
121
|
* @param error - The error to format.
|
|
@@ -106,11 +130,12 @@ export function formatViemError(error: any, abi: Abi = ErrorsAbi): FormattedViem
|
|
|
106
130
|
|
|
107
131
|
// First try to decode as a custom error using the ABI
|
|
108
132
|
try {
|
|
109
|
-
|
|
133
|
+
const data = getNestedErrorData(error);
|
|
134
|
+
if (data) {
|
|
110
135
|
// Try to decode the error data using the ABI
|
|
111
136
|
const decoded = decodeErrorResult({
|
|
112
137
|
abi,
|
|
113
|
-
data:
|
|
138
|
+
data: data as Hex,
|
|
114
139
|
});
|
|
115
140
|
if (decoded) {
|
|
116
141
|
return new FormattedViemError(`${decoded.errorName}(${decoded.args?.join(', ') ?? ''})`, error?.metaMessages);
|
|
@@ -120,6 +145,7 @@ export function formatViemError(error: any, abi: Abi = ErrorsAbi): FormattedViem
|
|
|
120
145
|
// If it's a BaseError, try to get the custom error through ContractFunctionRevertedError
|
|
121
146
|
if (error instanceof BaseError) {
|
|
122
147
|
const revertError = error.walk(err => err instanceof ContractFunctionRevertedError);
|
|
148
|
+
|
|
123
149
|
if (revertError instanceof ContractFunctionRevertedError) {
|
|
124
150
|
let errorName = revertError.data?.errorName;
|
|
125
151
|
if (!errorName) {
|
|
@@ -138,7 +164,7 @@ export function formatViemError(error: any, abi: Abi = ErrorsAbi): FormattedViem
|
|
|
138
164
|
|
|
139
165
|
// If it's a regular Error instance, return it with its message
|
|
140
166
|
if (error instanceof Error) {
|
|
141
|
-
return
|
|
167
|
+
return error;
|
|
142
168
|
}
|
|
143
169
|
|
|
144
170
|
// Original formatting logic for non-custom errors
|