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

Commit 119dfa5

Browse files
authored
Errors not caught in 4.x (#6623)
* catch TransactionPollingTimeoutError * add contract tests * eslint fix * text fixes * fix * increase coverage * fix * changelog
1 parent 7461c8e commit 119dfa5

File tree

8 files changed

+248
-10
lines changed

8 files changed

+248
-10
lines changed

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,3 +2254,36 @@ If there are any bugs, improvements, optimizations or any new feature proposal f
22542254
- Will populate `data` for transactions in contract for metamask provider instead of `input` (#6534)
22552255

22562256
## [Unreleased]
2257+
2258+
### Added
2259+
2260+
#### web3
2261+
2262+
2263+
#### web3-eth
2264+
2265+
- Catch `TransactionPollingTimeoutError` was added to send transaction events (#6623)
2266+
2267+
#### web3-utils
2268+
2269+
- `SocketProvider` now contains public function `getPendingRequestQueueSize`, `getSentRequestsQueueSize` and `clearQueues` (#6479)
2270+
- Added `safeDisconnect` as a `SocketProvider` method to disconnect only when request queue size and send request queue size is 0 (#6479)
2271+
- Add `isContractInitOptions` method (#6555)
2272+
2273+
### Changed
2274+
2275+
#### web3-core
2276+
2277+
2278+
#### web3-eth-contract
2279+
2280+
2281+
### Fixed
2282+
2283+
#### web3-rpc-methods
2284+
2285+
- Fix web3-types import #6590 (#6589)
2286+
2287+
#### web3-utils
2288+
2289+
- Fix unecessary array copy when pack encoding (#6553)

packages/web3-eth-accounts/src/tx/baseTransaction.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -421,10 +421,12 @@ export abstract class BaseTransaction<TransactionObject> {
421421
}
422422
// No chain ID provided
423423
// -> return Common provided or create new default Common
424-
return (
425-
common?.copy() ??
426-
new Common({ chain: this.DEFAULT_CHAIN, hardfork: this.DEFAULT_HARDFORK })
427-
);
424+
425+
if (common?.copy && typeof common?.copy === 'function') {
426+
return common.copy();
427+
}
428+
429+
return new Common({ chain: this.DEFAULT_CHAIN, hardfork: this.DEFAULT_HARDFORK });
428430
}
429431

430432
/**

packages/web3-eth-contract/test/integration/contract_erc20.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,66 @@ describe('contract', () => {
120120
value,
121121
);
122122
});
123+
124+
it('send tokens from the account that does not have ether', async () => {
125+
const tempAccount = await createTempAccount();
126+
const test = await createNewAccount({
127+
unlock: true,
128+
refill: false,
129+
});
130+
131+
let catchError = false;
132+
let catchErrorPromise;
133+
try {
134+
const promiEvent = contractDeployed.methods
135+
.transfer(tempAccount.address, '0x1')
136+
.send({ ...sendOptions, from: test.address });
137+
138+
catchErrorPromise = new Promise(resolve => {
139+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
140+
promiEvent.on('error', err => {
141+
// Returned error: insufficient funds for gas * price + value: balance 0, tx cost 25000327300000000, overshot 25000327300000000
142+
resolve(err);
143+
});
144+
});
145+
await promiEvent;
146+
} catch (e) {
147+
// Returned error: insufficient funds for gas * price + value: balance 0, tx cost 25000327300000000, overshot 25000327300000000
148+
catchError = true;
149+
}
150+
expect(await catchErrorPromise).toBeDefined();
151+
expect(catchError).toBe(true);
152+
});
153+
it('send tokens from the account that does not have tokens', async () => {
154+
const tempAccount = await createTempAccount();
155+
const test = await createNewAccount({
156+
unlock: true,
157+
refill: true,
158+
});
159+
160+
let catchError = false;
161+
let catchErrorPromise;
162+
try {
163+
const promiEvent = contractDeployed.methods
164+
.transfer(tempAccount.address, '0x1')
165+
.send({ ...sendOptions, from: test.address });
166+
167+
catchErrorPromise = new Promise(resolve => {
168+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
169+
promiEvent.on('error', err => {
170+
// Transaction has been reverted by the EVM
171+
resolve(err);
172+
});
173+
});
174+
await promiEvent;
175+
} catch (e) {
176+
// Transaction has been reverted by the EVM
177+
catchError = true;
178+
}
179+
expect(await catchErrorPromise).toBeDefined();
180+
expect(catchError).toBe(true);
181+
});
182+
123183
it.each([signAndSendContractMethodEIP1559, signAndSendContractMethodEIP2930])(
124184
'should transfer tokens with local wallet %p',
125185
async signAndSendContractMethod => {

packages/web3-eth/CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,8 @@ Documentation:
213213

214214
- Dependencies updated
215215

216-
## [Unreleased]
216+
## [Unreleased]
217+
218+
### Added
219+
220+
- Catch `TransactionPollingTimeoutError` was added to send transaction events (#6623)

packages/web3-eth/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
TransactionRevertInstructionError,
2222
TransactionRevertWithCustomError,
2323
InvalidResponseError,
24+
TransactionPollingTimeoutError,
2425
} from 'web3-errors';
2526
import {
2627
FormatType,
@@ -50,6 +51,7 @@ export type SendTransactionEventsBase<ReturnFormat extends DataFormat, TxType> =
5051
| TransactionRevertedWithoutReasonError<FormatType<TransactionReceipt, ReturnFormat>>
5152
| TransactionRevertInstructionError<FormatType<TransactionReceipt, ReturnFormat>>
5253
| TransactionRevertWithCustomError<FormatType<TransactionReceipt, ReturnFormat>>
54+
| TransactionPollingTimeoutError
5355
| InvalidResponseError
5456
| ContractExecutionError;
5557
};

packages/web3-eth/src/utils/send_tx_helper.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { isNullish } from 'web3-validator';
3737
import {
3838
ContractExecutionError,
3939
InvalidResponseError,
40+
TransactionPollingTimeoutError,
4041
TransactionRevertedWithoutReasonError,
4142
TransactionRevertInstructionError,
4243
TransactionRevertWithCustomError,
@@ -243,7 +244,8 @@ export class SendTxHelper<
243244
_error instanceof ContractExecutionError ||
244245
_error instanceof TransactionRevertWithCustomError ||
245246
_error instanceof TransactionRevertedWithoutReasonError ||
246-
_error instanceof TransactionRevertInstructionError) &&
247+
_error instanceof TransactionRevertInstructionError ||
248+
_error instanceof TransactionPollingTimeoutError) &&
247249
this.promiEvent.listenerCount('error') > 0
248250
) {
249251
this.promiEvent.emit('error', _error);

packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { isHexStrict } from 'web3-validator';
3333
import { Web3Eth, InternalTransaction, transactionSchema } from '../../../src';
3434
import {
3535
closeOpenConnection,
36+
createNewAccount,
3637
createTempAccount,
3738
getSystemTestBackend,
3839
getSystemTestProvider,
@@ -55,6 +56,74 @@ describe('Web3Eth.sendSignedTransaction', () => {
5556
await closeOpenConnection(web3Eth);
5657
});
5758

59+
describe('Should catch errors', () => {
60+
it('send ether from the account that does not have ether', async () => {
61+
let onErrorReceived = false;
62+
let catchErrorReceived = false;
63+
const from = await createNewAccount({
64+
unlock: true,
65+
refill: false,
66+
});
67+
let pr;
68+
try {
69+
const promiEvent = web3Eth.sendTransaction({
70+
to: tempAcc.address,
71+
from: from.address,
72+
});
73+
pr = new Promise(resolve => {
74+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
75+
promiEvent.on('error', () => {
76+
onErrorReceived = true;
77+
resolve(true);
78+
});
79+
});
80+
await promiEvent;
81+
} catch (e) {
82+
catchErrorReceived = true;
83+
}
84+
await pr;
85+
expect(onErrorReceived).toBe(true);
86+
expect(catchErrorReceived).toBe(true);
87+
});
88+
it('send and wait timeout', async () => {
89+
let onErrorReceived = false;
90+
let catchErrorReceived = false;
91+
const from = await createNewAccount({
92+
unlock: true,
93+
refill: true,
94+
});
95+
96+
web3Eth.setConfig({
97+
transactionReceiptPollingInterval: 10,
98+
transactionPollingTimeout: 1000,
99+
});
100+
101+
const currentNonce = await web3Eth.getTransactionCount(from.address);
102+
let pr;
103+
try {
104+
const promiEvent = web3Eth.sendTransaction({
105+
to: tempAcc.address,
106+
from: from.address,
107+
value: '0x1',
108+
nonce: currentNonce + BigInt(1000),
109+
});
110+
pr = new Promise(resolve => {
111+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
112+
promiEvent.on('error', () => {
113+
onErrorReceived = true;
114+
resolve(true);
115+
});
116+
});
117+
await promiEvent;
118+
} catch (e) {
119+
catchErrorReceived = true;
120+
}
121+
await pr;
122+
expect(onErrorReceived).toBe(true);
123+
expect(catchErrorReceived).toBe(true);
124+
});
125+
});
126+
58127
describe('Transaction Types', () => {
59128
it('should send a signed simple value transfer - type 0x0', async () => {
60129
const temp = await createTempAccount();

packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,25 @@ You should have received a copy of the GNU Lesser General Public License
1515
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

18-
import { EthExecutionAPI } from 'web3-types';
18+
import {
19+
Common,
20+
EthExecutionAPI,
21+
HexString,
22+
Web3NetAPI,
23+
Transaction as TransactionType,
24+
} from 'web3-types';
1925
import { Web3Context } from 'web3-core';
2026
import HttpProvider from 'web3-providers-http';
2127
import { isNullish } from 'web3-validator';
28+
29+
import { ethRpcMethods } from 'web3-rpc-methods';
30+
31+
import { bytesToHex, hexToBytes } from 'web3-utils';
2232
import {
2333
AccessListEIP2930Transaction,
2434
FeeMarketEIP1559Transaction,
2535
Transaction,
2636
} from 'web3-eth-accounts';
27-
import { ethRpcMethods } from 'web3-rpc-methods';
28-
29-
import { bytesToHex, hexToBytes } from 'web3-utils';
3037
import { prepareTransactionForSigning } from '../../src/utils/prepare_transaction_for_signing';
3138
import { validTransactions } from '../fixtures/prepare_transaction_for_signing';
3239

@@ -36,6 +43,65 @@ describe('prepareTransactionForSigning', () => {
3643
config: { defaultNetworkId: '0x1' },
3744
});
3845

46+
describe('default', () => {
47+
it('use default common', async () => {
48+
const context = new Web3Context<EthExecutionAPI>({
49+
provider: new HttpProvider('http://127.0.0.1'),
50+
config: { defaultNetworkId: '0x1' },
51+
});
52+
context.defaultChain = 'mainnet';
53+
context.defaultCommon = {
54+
customChain: {
55+
name: 'test',
56+
networkId: 457,
57+
chainId: 1458,
58+
},
59+
baseChain: 'mainnet',
60+
};
61+
62+
async function transactionBuilder<ReturnType = TransactionType>(options: {
63+
transaction: TransactionType;
64+
web3Context: Web3Context<EthExecutionAPI & Web3NetAPI>;
65+
privateKey?: HexString | Uint8Array;
66+
fillGasPrice?: boolean;
67+
fillGasLimit?: boolean;
68+
}): Promise<ReturnType> {
69+
const tx = { ...options.transaction };
70+
71+
if (isNullish(tx.common)) {
72+
if (options.web3Context.defaultCommon) {
73+
const common = options.web3Context.defaultCommon as unknown as Common;
74+
const chainId = common.customChain.chainId as string;
75+
const networkId = common.customChain.networkId as string;
76+
const name = common.customChain.name as string;
77+
tx.common = {
78+
...common,
79+
customChain: { chainId, networkId, name },
80+
};
81+
}
82+
}
83+
return tx as unknown as ReturnType;
84+
}
85+
86+
context.transactionBuilder = transactionBuilder;
87+
88+
const ethereumjsTx = await prepareTransactionForSigning(
89+
{
90+
chainId: 1458,
91+
nonce: 1,
92+
gasPrice: BigInt(20000000000),
93+
gas: BigInt(21000),
94+
to: '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55',
95+
from: '0x2c7536E3605D9C16a7a3D7b1898e529396a65c23',
96+
value: '1000000000',
97+
input: '',
98+
},
99+
context,
100+
);
101+
expect(Number(ethereumjsTx.common.networkId())).toBe(457);
102+
expect(ethereumjsTx.common.chainName()).toBe('test');
103+
});
104+
});
39105
describe('should return an web3-utils/tx instance with expected properties', () => {
40106
it.each(validTransactions)(
41107
'mockBlock: %s\nexpectedTransaction: %s\nexpectedPrivateKey: %s\nexpectedAddress: %s\nexpectedRlpEncodedTransaction: %s\nexpectedTransactionHash: %s\nexpectedMessageToSign: %s\nexpectedV: %s\nexpectedR: %s\nexpectedS: %s',

0 commit comments

Comments
 (0)