Skip to content
This repository has been archived by the owner on Mar 5, 2025. It is now read-only.

Use Error ABI to parse errors when sending a transaction #5662

Merged
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,10 @@ should use 4.0.1-alpha.0 for testing.

### Added

#### web3-eth-contract

- Decoding error data, using Error ABI if available, if error was returned from a smart contract function call (#5662).

#### web3-types

- These types were moved from `web3-eth-accounts` to `web3-types` package: Cipher, CipherOptions, ScryptParams, PBKDF2SHA256Params, KeyStore (#5581 )
Expand Down
4 changes: 4 additions & 0 deletions packages/web3-eth-contract/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ const transactionHash = receipt.transactionHash;

## [Unreleased]

### Added

- Decoding error data, using Error ABI if available, if error was returned from a smart contract function call (#5662).

### Fixed

- Emit past contract events based on `fromBlock` when passed to `contract.events.someEventName` (#5201)
Expand Down
24 changes: 16 additions & 8 deletions packages/web3-eth-contract/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,7 @@ export class Contract<Abi extends ContractAbi>
call: async (options?: PayableCallOptions, block?: BlockNumberOrTag) =>
this._contractMethodCall(methodAbi, abiParams, errorsAbis, options, block),
send: (options?: PayableTxOptions) =>
this._contractMethodSend(methodAbi, abiParams, options), // TODO: refactor to parse errorsAbi #5587
this._contractMethodSend(methodAbi, abiParams, errorsAbis, options),
estimateGas: async <
ReturnFormat extends DataFormat = typeof DEFAULT_RETURN_FORMAT,
>(
Expand All @@ -1062,7 +1062,7 @@ export class Contract<Abi extends ContractAbi>
call: async (options?: NonPayableCallOptions, block?: BlockNumberOrTag) =>
this._contractMethodCall(methodAbi, abiParams, errorsAbis, options, block),
send: (options?: NonPayableTxOptions) =>
this._contractMethodSend(methodAbi, abiParams, options), // TODO: refactor to parse errorsAbi #5587
this._contractMethodSend(methodAbi, abiParams, errorsAbis, options),
estimateGas: async <ReturnFormat extends DataFormat = typeof DEFAULT_RETURN_FORMAT>(
options?: NonPayableCallOptions,
returnFormat: ReturnFormat = DEFAULT_RETURN_FORMAT as ReturnFormat,
Expand All @@ -1081,13 +1081,10 @@ export class Contract<Abi extends ContractAbi>
};
}

private async _contractMethodCall<
E extends AbiErrorFragment,
Options extends PayableCallOptions | NonPayableCallOptions,
>(
private async _contractMethodCall<Options extends PayableCallOptions | NonPayableCallOptions>(
abi: AbiFunctionFragment,
params: unknown[],
errorsAbi: E[],
errorsAbi: AbiErrorFragment[],
options?: Options,
block?: BlockNumberOrTag,
) {
Expand Down Expand Up @@ -1115,6 +1112,7 @@ export class Contract<Abi extends ContractAbi>
private _contractMethodSend<Options extends PayableCallOptions | NonPayableCallOptions>(
abi: AbiFunctionFragment,
params: unknown[],
errorsAbi: AbiErrorFragment[],
options?: Options,
contractOptions?: ContractOptions,
) {
Expand All @@ -1132,7 +1130,17 @@ export class Contract<Abi extends ContractAbi>
contractOptions: modifiedContractOptions,
});

return sendTransaction(this, tx, DEFAULT_RETURN_FORMAT);
const promiEvent = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT);

// eslint-disable-next-line @typescript-eslint/no-floating-promises
promiEvent.on('error', (error: unknown) => {
if (error instanceof ContractExecutionError) {
// this will parse the error data by trying to decode the ABI error inputs according to EIP-838
decodeErrorData(errorsAbi, error.innerError);
}
});

return promiEvent;
}

private _contractMethodDeploySend<Options extends PayableCallOptions | NonPayableCallOptions>(
Expand Down
10 changes: 6 additions & 4 deletions packages/web3-eth-contract/test/unit/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,13 @@ describe('Contract', () => {
) {
// eslint-disable-next-line
expect(_tx.to).toStrictEqual(deployedAddr);
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return Promise.resolve({ status: '0x1' }) as any;

// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function
return { status: '0x1', on: () => {} } as any;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return Promise.resolve(newContract) as any;

// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function
return Promise.resolve(Object.assign(newContract, { on: () => {} })) as any;
});

const deployedContract = await contract
Expand Down