Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Errors not caught in 4.x #6623

Merged
merged 12 commits into from
Dec 4, 2023
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2254,3 +2254,36 @@ If there are any bugs, improvements, optimizations or any new feature proposal f
- Will populate `data` for transactions in contract for metamask provider instead of `input` (#6534)

## [Unreleased]

### Added

#### web3


#### web3-eth

- Catch `TransactionPollingTimeoutError` was added to send transaction events (#6623)

#### web3-utils

- `SocketProvider` now contains public function `getPendingRequestQueueSize`, `getSentRequestsQueueSize` and `clearQueues` (#6479)
- Added `safeDisconnect` as a `SocketProvider` method to disconnect only when request queue size and send request queue size is 0 (#6479)
- Add `isContractInitOptions` method (#6555)

### Changed

#### web3-core


#### web3-eth-contract


### Fixed

#### web3-rpc-methods

- Fix web3-types import #6590 (#6589)

#### web3-utils

- Fix unecessary array copy when pack encoding (#6553)
10 changes: 6 additions & 4 deletions packages/web3-eth-accounts/src/tx/baseTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,10 +421,12 @@ export abstract class BaseTransaction<TransactionObject> {
}
// No chain ID provided
// -> return Common provided or create new default Common
return (
common?.copy() ??
new Common({ chain: this.DEFAULT_CHAIN, hardfork: this.DEFAULT_HARDFORK })
);

if (common?.copy && typeof common?.copy === 'function') {
return common.copy();
}

return new Common({ chain: this.DEFAULT_CHAIN, hardfork: this.DEFAULT_HARDFORK });
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,66 @@ describe('contract', () => {
value,
);
});

it('send tokens from the account that does not have ether', async () => {
const tempAccount = await createTempAccount();
const test = await createNewAccount({
unlock: true,
refill: false,
});

let catchError = false;
let catchErrorPromise;
try {
const promiEvent = contractDeployed.methods
.transfer(tempAccount.address, '0x1')
.send({ ...sendOptions, from: test.address });

catchErrorPromise = new Promise(resolve => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
promiEvent.on('error', err => {
// Returned error: insufficient funds for gas * price + value: balance 0, tx cost 25000327300000000, overshot 25000327300000000
resolve(err);
});
});
await promiEvent;
} catch (e) {
// Returned error: insufficient funds for gas * price + value: balance 0, tx cost 25000327300000000, overshot 25000327300000000
catchError = true;
}
expect(await catchErrorPromise).toBeDefined();
expect(catchError).toBe(true);
});
it('send tokens from the account that does not have tokens', async () => {
const tempAccount = await createTempAccount();
const test = await createNewAccount({
unlock: true,
refill: true,
});

let catchError = false;
let catchErrorPromise;
try {
const promiEvent = contractDeployed.methods
.transfer(tempAccount.address, '0x1')
.send({ ...sendOptions, from: test.address });

catchErrorPromise = new Promise(resolve => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
promiEvent.on('error', err => {
// Transaction has been reverted by the EVM
resolve(err);
});
});
await promiEvent;
} catch (e) {
// Transaction has been reverted by the EVM
catchError = true;
}
expect(await catchErrorPromise).toBeDefined();
expect(catchError).toBe(true);
});

it.each([signAndSendContractMethodEIP1559, signAndSendContractMethodEIP2930])(
'should transfer tokens with local wallet %p',
async signAndSendContractMethod => {
Expand Down
6 changes: 5 additions & 1 deletion packages/web3-eth/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,8 @@ Documentation:

- Dependencies updated

## [Unreleased]
## [Unreleased]

### Added

- Catch `TransactionPollingTimeoutError` was added to send transaction events (#6623)
2 changes: 2 additions & 0 deletions packages/web3-eth/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
TransactionRevertInstructionError,
TransactionRevertWithCustomError,
InvalidResponseError,
TransactionPollingTimeoutError,
} from 'web3-errors';
import {
FormatType,
Expand Down Expand Up @@ -50,6 +51,7 @@ export type SendTransactionEventsBase<ReturnFormat extends DataFormat, TxType> =
| TransactionRevertedWithoutReasonError<FormatType<TransactionReceipt, ReturnFormat>>
| TransactionRevertInstructionError<FormatType<TransactionReceipt, ReturnFormat>>
| TransactionRevertWithCustomError<FormatType<TransactionReceipt, ReturnFormat>>
| TransactionPollingTimeoutError
| InvalidResponseError
| ContractExecutionError;
};
Expand Down
4 changes: 3 additions & 1 deletion packages/web3-eth/src/utils/send_tx_helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import {
ContractExecutionError,
InvalidResponseError,
TransactionPollingTimeoutError,
TransactionRevertedWithoutReasonError,
TransactionRevertInstructionError,
TransactionRevertWithCustomError,
Expand Down Expand Up @@ -243,7 +244,8 @@
_error instanceof ContractExecutionError ||
_error instanceof TransactionRevertWithCustomError ||
_error instanceof TransactionRevertedWithoutReasonError ||
_error instanceof TransactionRevertInstructionError) &&
_error instanceof TransactionRevertInstructionError ||
_error instanceof TransactionPollingTimeoutError) &&

Check warning on line 248 in packages/web3-eth/src/utils/send_tx_helper.ts

View check run for this annotation

Codecov / codecov/patch

packages/web3-eth/src/utils/send_tx_helper.ts#L247-L248

Added lines #L247 - L248 were not covered by tests
this.promiEvent.listenerCount('error') > 0
) {
this.promiEvent.emit('error', _error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { isHexStrict } from 'web3-validator';
import { Web3Eth, InternalTransaction, transactionSchema } from '../../../src';
import {
closeOpenConnection,
createNewAccount,
createTempAccount,
getSystemTestBackend,
getSystemTestProvider,
Expand All @@ -55,6 +56,74 @@ describe('Web3Eth.sendSignedTransaction', () => {
await closeOpenConnection(web3Eth);
});

describe('Should catch errors', () => {
it('send ether from the account that does not have ether', async () => {
let onErrorReceived = false;
let catchErrorReceived = false;
const from = await createNewAccount({
unlock: true,
refill: false,
});
let pr;
try {
const promiEvent = web3Eth.sendTransaction({
to: tempAcc.address,
from: from.address,
});
pr = new Promise(resolve => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
promiEvent.on('error', () => {
onErrorReceived = true;
resolve(true);
});
});
await promiEvent;
} catch (e) {
catchErrorReceived = true;
}
await pr;
expect(onErrorReceived).toBe(true);
expect(catchErrorReceived).toBe(true);
});
it('send and wait timeout', async () => {
let onErrorReceived = false;
let catchErrorReceived = false;
const from = await createNewAccount({
unlock: true,
refill: true,
});

web3Eth.setConfig({
transactionReceiptPollingInterval: 10,
transactionPollingTimeout: 1000,
});

const currentNonce = await web3Eth.getTransactionCount(from.address);
let pr;
try {
const promiEvent = web3Eth.sendTransaction({
to: tempAcc.address,
from: from.address,
value: '0x1',
nonce: currentNonce + BigInt(1000),
});
pr = new Promise(resolve => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
promiEvent.on('error', () => {
onErrorReceived = true;
resolve(true);
});
});
await promiEvent;
} catch (e) {
catchErrorReceived = true;
}
await pr;
expect(onErrorReceived).toBe(true);
expect(catchErrorReceived).toBe(true);
});
});

describe('Transaction Types', () => {
it('should send a signed simple value transfer - type 0x0', async () => {
const temp = await createTempAccount();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,25 @@ You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

import { EthExecutionAPI } from 'web3-types';
import {
Common,
EthExecutionAPI,
HexString,
Web3NetAPI,
Transaction as TransactionType,
} from 'web3-types';
import { Web3Context } from 'web3-core';
import HttpProvider from 'web3-providers-http';
import { isNullish } from 'web3-validator';

import { ethRpcMethods } from 'web3-rpc-methods';

import { bytesToHex, hexToBytes } from 'web3-utils';
import {
AccessListEIP2930Transaction,
FeeMarketEIP1559Transaction,
Transaction,
} from 'web3-eth-accounts';
import { ethRpcMethods } from 'web3-rpc-methods';

import { bytesToHex, hexToBytes } from 'web3-utils';
import { prepareTransactionForSigning } from '../../src/utils/prepare_transaction_for_signing';
import { validTransactions } from '../fixtures/prepare_transaction_for_signing';

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

describe('default', () => {
it('use default common', async () => {
const context = new Web3Context<EthExecutionAPI>({
provider: new HttpProvider('http://127.0.0.1'),
config: { defaultNetworkId: '0x1' },
});
context.defaultChain = 'mainnet';
context.defaultCommon = {
customChain: {
name: 'test',
networkId: 457,
chainId: 1458,
},
baseChain: 'mainnet',
};

async function transactionBuilder<ReturnType = TransactionType>(options: {
transaction: TransactionType;
web3Context: Web3Context<EthExecutionAPI & Web3NetAPI>;
privateKey?: HexString | Uint8Array;
fillGasPrice?: boolean;
fillGasLimit?: boolean;
}): Promise<ReturnType> {
const tx = { ...options.transaction };

if (isNullish(tx.common)) {
if (options.web3Context.defaultCommon) {
const common = options.web3Context.defaultCommon as unknown as Common;
const chainId = common.customChain.chainId as string;
const networkId = common.customChain.networkId as string;
const name = common.customChain.name as string;
tx.common = {
...common,
customChain: { chainId, networkId, name },
};
}
}
return tx as unknown as ReturnType;
}

context.transactionBuilder = transactionBuilder;

const ethereumjsTx = await prepareTransactionForSigning(
{
chainId: 1458,
nonce: 1,
gasPrice: BigInt(20000000000),
gas: BigInt(21000),
to: '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55',
from: '0x2c7536E3605D9C16a7a3D7b1898e529396a65c23',
value: '1000000000',
input: '',
},
context,
);
expect(Number(ethereumjsTx.common.networkId())).toBe(457);
expect(ethereumjsTx.common.chainName()).toBe('test');
});
});
describe('should return an web3-utils/tx instance with expected properties', () => {
it.each(validTransactions)(
'mockBlock: %s\nexpectedTransaction: %s\nexpectedPrivateKey: %s\nexpectedAddress: %s\nexpectedRlpEncodedTransaction: %s\nexpectedTransactionHash: %s\nexpectedMessageToSign: %s\nexpectedV: %s\nexpectedR: %s\nexpectedS: %s',
Expand Down
Loading