Skip to content

Commit

Permalink
add ignoregaspricing config (#7320)
Browse files Browse the repository at this point in the history
* add ignoregaspricing config

* update

* add tests

* update changelog and docs

* update docs and changelog

* format

* close connection
  • Loading branch information
luu-alex authored Oct 16, 2024
1 parent 7008e5c commit 69187c5
Show file tree
Hide file tree
Showing 14 changed files with 210 additions and 10 deletions.
22 changes: 22 additions & 0 deletions docs/docs/guides/02_web3_providers_guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,28 @@ await web3.eth.getBlockNumber();
// ↳ 18849658n
```

#### Websocket Providers will only terminate when closed

When connected to a WebSocket provider, the program will not automatically terminate after the code finishes running. This is to ensure the WebSocket connection remains open, allowing the program to continue listening for events.

The program will remain active until you explicitly disconnect from the WebSocket provider:

```ts
const web3 = new Web3(wsUrl);
// The program will keep running to listen for events.
```

#### Terminating the Program

When you're ready to stop the program, you can manually disconnect from the WebSocket provider by calling the disconnect method. This will properly close the connection and terminate the program:

```ts
const web3 = new Web3(wsUrl);
// When you are ready to terminate your program
web3.currentProvider?.disconnect();
// The program will now terminate
```

#### Configuring WebSocket Providers

The [`WebSocketProvider` constructor](/api/web3-providers-ws/class/WebSocketProvider#constructor) accepts two optional parameters that can be used to configure the behavior of the `WebSocketProvider`: the first parameter must be of type [`ClientRequestArgs`](https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules__types_node_http_d_._http_.clientrequestargs.html) or of [`ClientOptions`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e5ee5eae6a592198e469ad9f412bab8d223fcbb6/types/ws/index.d.ts#L243) and the second parameter must be of type [`ReconnectOptions`](/api/web3/namespace/utils#ReconnectOptions).
Expand Down
13 changes: 13 additions & 0 deletions docs/docs/guides/05_smart_contracts/tips_and_tricks.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ sidebar_label: 'Tips and Tricks'
📝 This article offers insights into **Smart Contracts** with helpful tips and tricks. If you have suggestions or questions, feel free to open an issue. We also welcome contributions through PRs.
:::

## Ignoring Web3.js autofill gas prices

When interacting with methods in contracts, Web3.js will automatically fill the gas. If you are using metamask or a similar provider and would rather have a suggestion elsewhere, the `ignoreGasPricing` option enables you to send transactions or interact with contracts without having web3.js automatically fill in the gas estimate.

#### Contract example

```ts
let contractDeployed: Contract<typeof BasicAbi>;
// instantiate contract...
contractDeployed.config.ignoreGasPricing = true;
const receipt = await contractDeployed.methods.setValues(1, 'string value', true).send(sendOptions);
```

## Calling Smart Contracts Methods with Parameter Overloading

### Overview of Function Overloading
Expand Down
28 changes: 28 additions & 0 deletions docs/docs/guides/09_web3_config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ There is list of configuration params that can be set for modifying behavior of
- [defaultMaxPriorityFeePerGas](/guides/web3_config/#defaultmaxpriorityfeepergas)
- [customTransactionSchema](/guides/web3_config/#customTransactionSchema)
- [defaultReturnFormat](/guides/web3_config/#defaultreturnformat)
- [ignoreGasPricing](/guides/web3_config/#ignoreGasPricing)

## Global level Config

Expand Down Expand Up @@ -477,3 +478,30 @@ export enum FMT_BYTES {
UINT8ARRAY = 'BYTES_UINT8ARRAY',
}
```

### [ignoreGasPricing]

The `ignoreGasPricing` option enables you to send transactions or interact with contracts without having web3.js automatically fill in the gas estimate. This feature is particularly useful when you prefer to let wallets or providers handle gas estimation instead.

#### Send transaction example

```ts
const web3 = new Web3(PROVIDER);
web3.config.ignoreGasPricing = true; // when setting configurations for the web3 object, this will also apply to newly created contracts from the web3 object
const transaction: TransactionWithToLocalWalletIndex = {
from: tempAcc.address,
to: '0x0000000000000000000000000000000000000000',
value: BigInt(1),
data: '0x64edfbf0e2c706ba4a09595315c45355a341a576cc17f3a19f43ac1c02f814ee',
};
const receipt = await web3.eth.sendTransaction(transaction); // web3.js will not estimate gas now.
```

#### Contract example

```ts
let contractDeployed: Contract<typeof BasicAbi>;
// instantiate contract...
contractDeployed.config.ignoreGasPricing = true;
const receipt = await contractDeployed.methods.setValues(1, 'string value', true).send(sendOptions);
```
4 changes: 4 additions & 0 deletions packages/web3-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,7 @@ Documentation:
- Adds a new property (`customTransactionSchema`) to `Web3ConfigOptions`(#7227)

## [Unreleased]

### Added

- Added new property `ignoreGasPricing` to `Web3ConfigOptions`. If `ignoreGasPricing` is true, gasPrice will not be estimated (#7320)
15 changes: 14 additions & 1 deletion packages/web3-core/src/web3_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export interface Web3ConfigOptions {
defaultNetworkId?: Numbers;
defaultChain: string;
defaultHardfork: string;
ignoreGasPricing: boolean;

defaultCommon?: Common;
defaultTransactionType: Numbers;
Expand Down Expand Up @@ -104,6 +105,7 @@ export abstract class Web3Config
transactionTypeParser: undefined,
customTransactionSchema: undefined,
defaultReturnFormat: DEFAULT_RETURN_FORMAT,
ignoreGasPricing: false,
};

public constructor(options?: Partial<Web3ConfigOptions>) {
Expand Down Expand Up @@ -208,7 +210,7 @@ export abstract class Web3Config
* - `"latest"` - String: The latest block (current head of the blockchain)
* - `"pending"` - String: The currently mined block (including pending transactions)
* - `"finalized"` - String: (For POS networks) The finalized block is one which has been accepted as canonical by greater than 2/3 of validators
* - `"safe"` - String: (For POS networks) The safe head block is one which under normal network conditions, is expected to be included in the canonical chain. Under normal network conditions the safe head and the actual tip of the chain will be equivalent (with safe head trailing only by a few seconds). Safe heads will be less likely to be reorged than the proof of work network`s latest blocks.
* - `"safe"` - String: (For POS networks) The safe head block is one which under normal network conditions, is expected to be included in the canonical chain. Under normal network conditions the safe head and the actual tip of the chain will be equivalent (with safe head trailing only by a few seconds). Safe heads will be less likely to be reorged than the proof of work network's latest blocks.
*/
public set defaultBlock(val) {
this._triggerConfigChange('defaultBlock', val);
Expand Down Expand Up @@ -485,6 +487,17 @@ export abstract class Web3Config
this.config.defaultCommon = val;
}

/**
* Will get the ignoreGasPricing property. When true, the gasPrice, maxPriorityFeePerGas, and maxFeePerGas will not be autofilled in the transaction object.
* Useful when you want wallets to handle gas pricing.
*/
public get ignoreGasPricing() {
return this.config.ignoreGasPricing;
}
public set ignoreGasPricing(val) {
this._triggerConfigChange('ignoreGasPricing', val);
this.config.ignoreGasPricing = val;
}
public get defaultTransactionType() {
return this.config.defaultTransactionType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ exports[`Web3Context getContextObject should return correct context object 1`] =
"useSubscriptionWhenCheckingBlockTimeout": false,
},
"handleRevert": false,
"ignoreGasPricing": false,
"maxListenersWarningThreshold": 100,
"transactionBlockTimeout": 50,
"transactionBuilder": undefined,
Expand Down
1 change: 1 addition & 0 deletions packages/web3-core/test/unit/web3_config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const defaultConfig = {
transactionBuilder: undefined,
transactionTypeParser: undefined,
customTransactionSchema: undefined,
ignoreGasPricing: false,
};
const setValue = {
string: 'newValue',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,48 @@ describe('contract', () => {
});

describe('send', () => {
it('should returns a receipt', async () => {
beforeEach(() => {
contractDeployed.config.ignoreGasPricing = false;
});
it('should return a receipt', async () => {
const receipt = await contractDeployed.methods
.setValues(1, 'string value', true)
.send(sendOptions);

expect(receipt.events).toBeUndefined();
expect(receipt).toEqual(
expect.objectContaining({
// status: BigInt(1),
transactionHash: expect.any(String),
}),
);

// To avoid issue with the `objectContaining` and `cypress` had to add
// these expectations explicitly on each attribute
expect(receipt.status).toEqual(BigInt(1));
});

it('should return a receipt with ignoring gas config true', async () => {
contractDeployed.config.ignoreGasPricing = true;
const receipt = await contractDeployed.methods
.setValues(1, 'string value', true)
.send(sendOptions);

expect(receipt.events).toBeUndefined();
expect(receipt).toEqual(
expect.objectContaining({
// status: BigInt(1),
transactionHash: expect.any(String),
}),
);

// To avoid issue with the `objectContaining` and `cypress` had to add
// these expectations explicitly on each attribute
expect(receipt.status).toEqual(BigInt(1));
});

it('should return a receipt with ignoring gas config false', async () => {
contractDeployed.config.ignoreGasPricing = false;
const receipt = await contractDeployed.methods
.setValues(1, 'string value', true)
.send(sendOptions);
Expand Down
4 changes: 4 additions & 0 deletions packages/web3-eth/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,7 @@ Documentation:
### Changed

- Allow `getEthereumjsTxDataFrom` to return additional fields that may be passed if using a `customTransactionSchema`.

### Added

- `populateGasPrice` function now checks `Web3Context.config.ignoreGasPricing`. If `ignoreGasPricing` is true, gasPrice will not be estimated (#7320)
1 change: 1 addition & 0 deletions packages/web3-eth/src/utils/send_tx_helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export class SendTxHelper<
}): Promise<TxType> {
let result = transactionFormatted;
if (
!this.web3Context.config.ignoreGasPricing &&
!this.options?.ignoreGasPricing &&
isNullish((transactionFormatted as Transaction).gasPrice) &&
(isNullish((transaction as Transaction).maxPriorityFeePerGas) ||
Expand Down
8 changes: 1 addition & 7 deletions packages/web3-eth/src/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,7 @@ import {
TransactionWithSenderAPI,
ETH_DATA_FORMAT,
} from 'web3-types';
import {
isAddress,
isHexStrict,
isHexString32Bytes,
isNullish,
isUInt,
} from 'web3-validator';
import { isAddress, isHexStrict, isHexString32Bytes, isNullish, isUInt } from 'web3-validator';
import {
ChainMismatchError,
HardforkMismatchError,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,34 @@ describe('Web3Eth.sendTransaction', () => {
const minedTransactionData = await web3Eth.getTransaction(response.transactionHash);
expect(minedTransactionData).toMatchObject(transaction);
});
it('should send a transaction while ignoring gas price successfully', async () => {
const transaction: TransactionWithToLocalWalletIndex = {
from: tempAcc.address,
to: '0x0000000000000000000000000000000000000000',
value: BigInt(1),
data: '0x64edfbf0e2c706ba4a09595315c45355a341a576cc17f3a19f43ac1c02f814ee',
};

const localWeb3Eth = new Web3Eth(getSystemTestProvider());
localWeb3Eth.config.ignoreGasPricing = true;
const response = await localWeb3Eth.sendTransaction(transaction);
expect(response.status).toBe(BigInt(1));
await closeOpenConnection(localWeb3Eth);
});
it('should send a transaction with automated gas price successfully', async () => {
const transaction: TransactionWithToLocalWalletIndex = {
from: tempAcc.address,
to: '0x0000000000000000000000000000000000000000',
value: BigInt(1),
data: '0x64edfbf0e2c706ba4a09595315c45355a341a576cc17f3a19f43ac1c02f814ee',
};

const localWeb3Eth = new Web3Eth(getSystemTestProvider());
localWeb3Eth.config.ignoreGasPricing = false;
const response = await localWeb3Eth.sendTransaction(transaction);
expect(response.status).toBe(BigInt(1));
await closeOpenConnection(localWeb3Eth);
});
describe('Deploy and interact with contract', () => {
let greeterContractAddress: string;

Expand Down
49 changes: 48 additions & 1 deletion packages/web3-eth/test/unit/send_tx_helper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ describe('sendTxHelper class', () => {
let sendTxHelper: SendTxHelper<DataFormat>;
let promiEvent: Web3PromiEvent<TransactionReceipt, Web3EventMap>;
let web3Context: Web3Context<EthExecutionAPI>;
beforeAll(() => {
beforeEach(() => {
jest.clearAllMocks();
web3Context = new Web3Context<EthExecutionAPI>();
promiEvent = new Web3PromiEvent<TransactionReceipt, Web3EventMap>(resolve => {
resolve({} as unknown as TransactionReceipt);
Expand Down Expand Up @@ -267,4 +268,50 @@ describe('sendTxHelper class', () => {
expect(utils.trySendTransaction).toHaveBeenCalled();
expect(wallet.signTransaction).toHaveBeenCalledWith(receipt);
});
it('should not call getTransactionGasPricing when ignoreGasPricing is true', async () => {
web3Context.config.ignoreGasPricing = true;
const transaction = {
from: '0xa7d9ddbe1f17865597fbd27ec712455208b6b76d',
input: '0x68656c6c6f21',
nonce: '0x15',
to: '0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb',
value: '0xf3dbb76162000',
type: '0x0',
chainId: '0x1',
};
const _sendTxHelper = new SendTxHelper({
web3Context,
promiEvent: promiEvent as PromiEvent,
options: {},
returnFormat: DEFAULT_RETURN_FORMAT,
});
await _sendTxHelper.populateGasPrice({
transactionFormatted: transaction,
transaction,
});
expect(getTransactionGasPricing).not.toHaveBeenCalled();
});
it('should call getTransactionGasPricing when ignoreGasPricing is false', async () => {
web3Context.config.ignoreGasPricing = false;
const transaction = {
from: '0xa7d9ddbe1f17865597fbd27ec712455208b6b76d',
input: '0x68656c6c6f21',
nonce: '0x15',
to: '0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb',
value: '0xf3dbb76162000',
type: '0x0',
chainId: '0x1',
};
const _sendTxHelper = new SendTxHelper({
web3Context,
promiEvent: promiEvent as PromiEvent,
options: {},
returnFormat: DEFAULT_RETURN_FORMAT,
});
await _sendTxHelper.populateGasPrice({
transactionFormatted: transaction,
transaction,
});
expect(getTransactionGasPricing).toHaveBeenCalled();
});
});
4 changes: 4 additions & 0 deletions packages/web3-types/src/eth_contract_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,8 @@ export interface ContractOptions {
* The max fee per gas to use for transactions.
*/
maxFeePerGas?: Uint;
/**
* Ignore gas price, turn on for metamask suggestion fee
*/
ignoreGasPricing?: boolean;
}

1 comment on commit 69187c5

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 69187c5 Previous: 7008e5c Ratio
processingTx 21197 ops/sec (±9.42%) 21737 ops/sec (±7.03%) 1.03
processingContractDeploy 39646 ops/sec (±7.16%) 40986 ops/sec (±5.05%) 1.03
processingContractMethodSend 16345 ops/sec (±6.62%) 16967 ops/sec (±6.53%) 1.04
processingContractMethodCall 27913 ops/sec (±6.12%) 28544 ops/sec (±6.19%) 1.02
abiEncode 44153 ops/sec (±6.91%) 44403 ops/sec (±6.90%) 1.01
abiDecode 30167 ops/sec (±8.30%) 31413 ops/sec (±5.50%) 1.04
sign 1554 ops/sec (±3.55%) 1547 ops/sec (±3.80%) 1.00
verify 362 ops/sec (±0.54%) 369 ops/sec (±0.66%) 1.02

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.