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

Commit d0d388b

Browse files
committed
Merge branch 'wyatt/4.x/5091-chainlink-plugin' of github.com:ChainSafe/web3.js into wyatt/4.x/5091-chainlink-plugin
2 parents 3233a76 + cb636c2 commit d0d388b

File tree

6 files changed

+175
-3
lines changed

6 files changed

+175
-3
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,9 @@ Released with 1.0.0-beta.37 code base.
602602

603603
## [4.0.0-alpha.0]
604604

605+
Note: Yarn is resolving to some old deprecated package versions for 4.0.0-alpha.0 instead of latest alpha versions. A patch bump is posted so yarn users
606+
should use 4.0.1-alpha.0 for testing.
607+
605608
### Added
606609

607610
#### web3-errors

packages/web3-core/src/web3_config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ export abstract class Web3Config
104104
* - myContract.methods.myMethod().call()
105105
* - myContract.methods.myMethod().send()
106106
* Default is `false`.
107+
*
108+
* `Note`: At the moment `handleRevert` is only supported for `sendTransaction` and not for `sendSignedTransaction`
107109
*/
108110
public get handleRevert() {
109111
return this._config.handleRevert;

packages/web3-errors/src/errors/transaction_errors.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ export class TransactionRevertError extends Web3Error {
6060

6161
public constructor(
6262
public reason: string,
63-
public signature: string,
64-
public receipt: TransactionReceipt,
63+
public signature?: string,
64+
public receipt?: TransactionReceipt,
6565
) {
6666
super(
6767
`Transaction has been reverted by the EVM:\n ${JSON.stringify(receipt, undefined, 2)}`,

packages/web3-eth/src/rpc_method_wrappers.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import {
5050
waitWithTimeout,
5151
} from 'web3-utils';
5252
import { isBlockTag, isBytes, isNullish, isString } from 'web3-validator';
53-
import { TransactionError } from 'web3-errors';
53+
import { TransactionError, TransactionRevertError } from 'web3-errors';
5454
import { SignatureError, TransactionSendTimeoutError } from './errors';
5555
import * as rpcMethods from './rpc_methods';
5656
import {
@@ -1071,6 +1071,15 @@ export function sendTransaction<
10711071
ETH_DATA_FORMAT,
10721072
);
10731073

1074+
if (web3Context.handleRevert) {
1075+
// eslint-disable-next-line no-use-before-define
1076+
await getRevertReason(
1077+
web3Context,
1078+
transactionFormatted as TransactionCall,
1079+
returnFormat,
1080+
);
1081+
}
1082+
10741083
if (
10751084
!options?.ignoreGasPricing &&
10761085
isNullish(transactionFormatted.gasPrice) &&
@@ -1320,6 +1329,11 @@ export function sendSignedTransaction<
13201329
if (promiEvent.listenerCount('sending') > 0) {
13211330
promiEvent.emit('sending', signedTransactionFormattedHex);
13221331
}
1332+
// todo enable handleRevert for sendSignedTransaction when we have a function to decode transactions
1333+
// importing a package for this would increase the size of the library
1334+
// if (web3Context.handleRevert) {
1335+
// await getRevertReason(web3Context, transaction, returnFormat);
1336+
// }
13231337

13241338
const transactionHash = await rpcMethods.sendRawTransaction(
13251339
web3Context.requestManager,
@@ -1893,3 +1907,19 @@ export async function getFeeHistory<ReturnFormat extends DataFormat>(
18931907

18941908
return format(feeHistorySchema, response as unknown as FeeHistory, returnFormat);
18951909
}
1910+
/**
1911+
*
1912+
* @param web3Context
1913+
* @param transaction
1914+
*/
1915+
async function getRevertReason<ReturnFormat extends DataFormat>(
1916+
web3Context: Web3Context<EthExecutionAPI>,
1917+
transaction: TransactionCall,
1918+
returnFormat: ReturnFormat,
1919+
) {
1920+
try {
1921+
await call(web3Context, transaction, web3Context.defaultBlock, returnFormat);
1922+
} catch (err) {
1923+
throw new TransactionRevertError((err as Error).message);
1924+
}
1925+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
This file is part of web3.js.
3+
4+
web3.js is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU Lesser General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
web3.js is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public License
15+
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
import WebSocketProvider from 'web3-providers-ws';
18+
import { Contract } from 'web3-eth-contract';
19+
import { TransactionRevertError } from 'web3-errors';
20+
import Web3 from '../../src/index';
21+
import {
22+
createNewAccount,
23+
getSystemTestProvider,
24+
isWs,
25+
} from '../shared_fixtures/system_tests_utils';
26+
import { BasicAbi, BasicBytecode } from '../shared_fixtures/build/Basic';
27+
28+
Error.stackTraceLimit = Infinity;
29+
30+
describe('eth', () => {
31+
let web3: Web3;
32+
let accounts: string[] = [];
33+
let clientUrl: string;
34+
35+
let contract: Contract<typeof BasicAbi>;
36+
let deployOptions: Record<string, unknown>;
37+
let sendOptions: Record<string, unknown>;
38+
39+
beforeAll(async () => {
40+
clientUrl = getSystemTestProvider();
41+
const acc1 = await createNewAccount({ unlock: true, refill: true });
42+
const acc2 = await createNewAccount({ unlock: true, refill: true });
43+
accounts = [acc1.address, acc2.address];
44+
web3 = new Web3(getSystemTestProvider());
45+
if (isWs) {
46+
web3 = new Web3(
47+
new WebSocketProvider(
48+
clientUrl,
49+
{},
50+
{ delay: 1, autoReconnect: false, maxAttempts: 1 },
51+
),
52+
);
53+
} else {
54+
web3 = new Web3(clientUrl);
55+
}
56+
57+
if (isWs) {
58+
contract = new web3.eth.Contract(BasicAbi, undefined, {
59+
provider: new WebSocketProvider(
60+
clientUrl,
61+
{},
62+
{ delay: 1, autoReconnect: false, maxAttempts: 1 },
63+
),
64+
});
65+
} else {
66+
contract = new web3.eth.Contract(BasicAbi, undefined, {
67+
provider: clientUrl,
68+
});
69+
}
70+
71+
deployOptions = {
72+
data: BasicBytecode,
73+
arguments: [10, 'string init value'],
74+
};
75+
76+
sendOptions = { from: accounts[0], gas: '1000000' };
77+
78+
contract = await contract.deploy(deployOptions).send(sendOptions);
79+
});
80+
afterAll(() => {
81+
if (isWs && web3?.provider) {
82+
(web3.provider as WebSocketProvider).disconnect();
83+
(contract.provider as WebSocketProvider).disconnect();
84+
}
85+
});
86+
87+
describe('handleRevert', () => {
88+
// todo enable when figure out what happening in eth_call (doesn't throw error)
89+
// eslint-disable-next-line jest/expect-expect
90+
it('should get revert reason', async () => {
91+
contract.handleRevert = true;
92+
await expect(contract.methods.reverts().send({ from: accounts[0] })).rejects.toThrow(
93+
new TransactionRevertError(
94+
'Returned error: execution reverted: REVERTED WITH REVERT',
95+
),
96+
);
97+
});
98+
99+
it('should get revert reason for eth tx', async () => {
100+
web3.eth.handleRevert = true;
101+
await expect(
102+
web3.eth.sendTransaction({
103+
from: accounts[0],
104+
gas: '0x3d0900',
105+
gasPrice: '0x3B9ACBF4',
106+
input: '0x608060405234801561001057600080fdklkl',
107+
nonce: '0x10',
108+
to: undefined,
109+
value: '0x0',
110+
type: '0x0',
111+
v: '0xa96',
112+
r: '0x1ba80b16306d1de8ff809c00f67c305e8636326096aba282828d331aa2ec30a1',
113+
s: '0x39f77e0b68d5524826e4385ad4e1f01e748f32c177840184ae65d9592fdfe5c',
114+
}),
115+
).rejects.toThrow(
116+
new TransactionRevertError(
117+
'Returned error: invalid argument 0: json: cannot unmarshal invalid hex string into Go struct field TransactionArgs.data of type hexutil.Bytes',
118+
),
119+
);
120+
});
121+
122+
it('should execute transaction', async () => {
123+
web3.eth.handleRevert = true;
124+
await expect(
125+
web3.eth.sendTransaction({
126+
from: accounts[0],
127+
to: accounts[1],
128+
gas: '0x76c0',
129+
gasPrice: '0x9184e72a000',
130+
value: '0x9184e72a',
131+
data: '0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675',
132+
}),
133+
).resolves.toBeDefined();
134+
});
135+
});
136+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../fixtures/build

0 commit comments

Comments
 (0)