@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.
Files changed (36) hide show
  1. package/dest/contracts/empire_base.d.ts +13 -0
  2. package/dest/contracts/empire_base.d.ts.map +1 -0
  3. package/dest/contracts/empire_base.js +10 -0
  4. package/dest/contracts/forwarder.d.ts +4 -3
  5. package/dest/contracts/forwarder.d.ts.map +1 -1
  6. package/dest/contracts/forwarder.js +29 -14
  7. package/dest/contracts/governance_proposer.d.ts +19 -4
  8. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  9. package/dest/contracts/governance_proposer.js +33 -2
  10. package/dest/contracts/index.d.ts +2 -1
  11. package/dest/contracts/index.d.ts.map +1 -1
  12. package/dest/contracts/index.js +3 -2
  13. package/dest/contracts/rollup.d.ts +2 -0
  14. package/dest/contracts/rollup.d.ts.map +1 -1
  15. package/dest/contracts/rollup.js +19 -9
  16. package/dest/contracts/slashing_proposer.d.ts +14 -4
  17. package/dest/contracts/slashing_proposer.d.ts.map +1 -1
  18. package/dest/contracts/slashing_proposer.js +19 -1
  19. package/dest/deploy_l1_contracts.d.ts +1448 -203
  20. package/dest/deploy_l1_contracts.d.ts.map +1 -1
  21. package/dest/deploy_l1_contracts.js +6 -2
  22. package/dest/l1_tx_utils.d.ts +7 -6
  23. package/dest/l1_tx_utils.d.ts.map +1 -1
  24. package/dest/l1_tx_utils.js +6 -17
  25. package/dest/utils.d.ts.map +1 -1
  26. package/dest/utils.js +25 -4
  27. package/package.json +3 -3
  28. package/src/contracts/empire_base.ts +19 -0
  29. package/src/contracts/forwarder.ts +37 -14
  30. package/src/contracts/governance_proposer.ts +54 -4
  31. package/src/contracts/index.ts +2 -1
  32. package/src/contracts/rollup.ts +20 -8
  33. package/src/contracts/slashing_proposer.ts +29 -2
  34. package/src/deploy_l1_contracts.ts +6 -0
  35. package/src/l1_tx_utils.ts +9 -19
  36. 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 data = encodeFunctionData({
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
- args: [toArgs, dataArgs],
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
- errorMsg = await l1TxUtils.tryGetErrorFromRevertedTx(data, args, {
101
- blobs: blobConfig.blobs,
102
- kzg: blobConfig.kzg,
103
- maxFeePerBlobGas,
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
- errorMsg = await l1TxUtils.tryGetErrorFromRevertedTx(data, args);
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
- export class GovernanceProposerContract {
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: PublicClient<HttpTransport, Chain>, address: Hex) {
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
  }
@@ -1,5 +1,6 @@
1
+ export * from './empire_base.js';
1
2
  export * from './forwarder.js';
2
- export * from './rollup.js';
3
3
  export * from './governance.js';
4
4
  export * from './governance_proposer.js';
5
+ export * from './rollup.js';
5
6
  export * from './slashing_proposer.js';
@@ -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.SLASHER();
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.GENESIS_TIME();
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.EPOCH_DURATION();
106
+ return this.rollup.read.getEpochDuration();
99
107
  }
100
108
 
101
109
  @memoize
102
110
  getSlotDuration() {
103
- return this.rollup.read.SLOT_DURATION();
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.MINIMUM_STAKE();
121
+ return this.rollup.read.getMinimumStake();
114
122
  }
115
123
 
116
124
  public async getSlashingProposerAddress() {
117
- const slasherAddress = await this.rollup.read.SLASHER();
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.STAKING_ASSET(),
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
- export class SlashingProposerContract {
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: PublicClient<HttpTransport, Chain>, address: Hex) {
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
  },
@@ -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: 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?: L1BlobInputs & { maxFeePerBlobGas: bigint },
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
- if (error?.data) {
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: error.data as Hex,
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 new FormattedViemError(error.message);
167
+ return error;
142
168
  }
143
169
 
144
170
  // Original formatting logic for non-custom errors