Skip to content

Commit

Permalink
allowing to specify percentage-based factors (like 1.125 for 112.5%) (#…
Browse files Browse the repository at this point in the history
…7332)

* allowing to specify percentage-based factors (like 1.125 for 112.5%)

* added change log

* implemented with backward compatibility for any existing users
logic handled according to number or bigint
added unit test

* Adjusted method description

---------

Co-authored-by: I744506 <temirlan.basitov@sap.com>
  • Loading branch information
TemirlanBasitov and I744506 authored Oct 30, 2024
1 parent efac906 commit 69d83e7
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 38 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2754,6 +2754,10 @@ If there are any bugs, improvements, optimizations or any new feature proposal f

- update the type for `baseFeePerGas` at `web3.eth.getFeeHistory` to be a number. (#7291)

#### web3-eth

- Allow specifying percentage based factor in Web3Eth.calculateFeeData Param baseFeePerGasFactor #7332

### Fixed

#### web3-eth-abi
Expand All @@ -2770,4 +2774,4 @@ If there are any bugs, improvements, optimizations or any new feature proposal f

#### web3-rpc-providers

- PublicNodeProvider was added (#7322)
- PublicNodeProvider was added (#7322)
96 changes: 59 additions & 37 deletions packages/web3-eth/src/web3_eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,43 +272,57 @@ export class Web3Eth extends Web3Context<Web3EthExecutionAPI, RegisteredSubscrip
}

/**
* Calculates the current Fee Data.
* If the node supports EIP-1559, then `baseFeePerGas` and `maxPriorityFeePerGas` will be returned along with the calculated `maxFeePerGas` value.
* `maxFeePerGas` is calculated as `baseFeePerGas` * `baseFeePerGasFactor` + `maxPriorityFeePerGas`.
* If the node does not support EIP-1559, then the `gasPrice` will be returned and the other values will be undefined.
*
* @param baseFeePerGasFactor (optional) The factor to multiply the `baseFeePerGas` with when calculating `maxFeePerGas`, if the node supports EIP-1559. The default value is 2.
* @param alternativeMaxPriorityFeePerGas (optional) The alternative `maxPriorityFeePerGas` to use when calculating `maxFeePerGas`, if the node supports EIP-1559, but does not support the method `eth_maxPriorityFeePerGas`. The default value is 1 gwei.
* @returns The current fee data.
*
* ```ts
* web3.eth.calculateFeeData().then(console.log);
* > {
* gasPrice: 20000000000n,
* maxFeePerGas: 60000000000n,
* maxPriorityFeePerGas: 20000000000n,
* baseFeePerGas: 20000000000n
* }
*
* web3.eth.calculateFeeData(1n).then(console.log);
* > {
* gasPrice: 20000000000n,
* maxFeePerGas: 40000000000n,
* maxPriorityFeePerGas: 20000000000n,
* baseFeePerGas: 20000000000n
* }
*
* web3.eth.calculateFeeData(3n).then(console.log);
* > {
* gasPrice: 20000000000n,
* maxFeePerGas: 80000000000n,
* maxPriorityFeePerGas: 20000000000n,
* baseFeePerGas: 20000000000n
* }
* ```
*/
* Calculates the current Fee Data.
* If the node supports EIP-1559, then `baseFeePerGas` and `maxPriorityFeePerGas` will be returned along with the calculated `maxFeePerGas` value.
* `maxFeePerGas` is calculated as `baseFeePerGas` * `baseFeePerGasFactor` + `maxPriorityFeePerGas`.
* If the node does not support EIP-1559, then the `gasPrice` will be returned and the other values will be undefined.
*
* @param baseFeePerGasFactor (optional) The factor to multiply the `baseFeePerGas` with when calculating `maxFeePerGas`, if the node supports EIP-1559. This can be a `bigint` for precise calculation or a `number` to support decimals. The default value is 2 (BigInt).
* If a `number` is provided, it will be converted to `bigint` with three decimal precision.
* @param alternativeMaxPriorityFeePerGas (optional) The alternative `maxPriorityFeePerGas` to use when calculating `maxFeePerGas`, if the node supports EIP-1559 but does not support the method `eth_maxPriorityFeePerGas`. The default value is 1 gwei.
* @returns The current fee data.
*
* @example
* web3.eth.calculateFeeData().then(console.log);
* > {
* gasPrice: 20000000000n,
* maxFeePerGas: 60000000000n,
* maxPriorityFeePerGas: 20000000000n,
* baseFeePerGas: 20000000000n
* }
*
* @example
* // Using a `bigint` for baseFeePerGasFactor
* web3.eth.calculateFeeData(1n).then(console.log);
* > {
* gasPrice: 20000000000n,
* maxFeePerGas: 40000000000n,
* maxPriorityFeePerGas: 20000000000n,
* baseFeePerGas: 20000000000n
* }
*
* @example
* // Using a `number` for baseFeePerGasFactor (with decimals)
* web3.eth.calculateFeeData(1.5).then(console.log);
* > {
* gasPrice: 20000000000n,
* maxFeePerGas: 50000000000n, // baseFeePerGasFactor is converted to BigInt(1.500)
* maxPriorityFeePerGas: 20000000000n,
* baseFeePerGas: 20000000000n
* }
*
* @example
* web3.eth.calculateFeeData(3n).then(console.log);
* > {
* gasPrice: 20000000000n,
* maxFeePerGas: 80000000000n,
* maxPriorityFeePerGas: 20000000000n,
* baseFeePerGas: 20000000000n
* }
*/

public async calculateFeeData(
baseFeePerGasFactor = BigInt(2),
baseFeePerGasFactor: bigint | number = BigInt(2),
alternativeMaxPriorityFeePerGas = ethUnitMap.Gwei,
): Promise<FeeData> {
const block = await this.getBlock<{ number: FMT_NUMBER.BIGINT; bytes: FMT_BYTES.HEX }>(
Expand Down Expand Up @@ -348,7 +362,15 @@ export class Web3Eth extends Web3Context<Web3EthExecutionAPI, RegisteredSubscrip
// and we multiply the `baseFeePerGas` by `baseFeePerGasFactor`, to allow
// trying to include the transaction in the next few blocks even if the
// baseFeePerGas is increasing fast
maxFeePerGas = baseFeePerGas * baseFeePerGasFactor + maxPriorityFeePerGas;
let baseFeeMultiplier: bigint;
if (typeof baseFeePerGasFactor === 'number') {
// Convert number to bigint with three decimal places
baseFeeMultiplier = BigInt(Math.floor(baseFeePerGasFactor * 1000)) / BigInt(1000);
} else {
// It's already a BigInt, so just use it as-is
baseFeeMultiplier = baseFeePerGasFactor;
}
maxFeePerGas = baseFeePerGas * baseFeeMultiplier + maxPriorityFeePerGas;
}

return { gasPrice, maxFeePerGas, maxPriorityFeePerGas, baseFeePerGas };
Expand Down
21 changes: 21 additions & 0 deletions packages/web3-eth/test/unit/web3_eth_calculate_fee_data.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,25 @@ describe('Web3Eth.calculateFeeData', () => {
baseFeePerGas,
});
});

it('should use default baseFeePerGasFactor if none is provided', async () => {
const gasPrice = BigInt(20 * 1000);
const baseFeePerGas = BigInt(1000);
const maxPriorityFeePerGas = BigInt(100); // this will be used directly

jest.spyOn(ethRpcMethods, 'getBlockByNumber').mockReturnValueOnce({ baseFeePerGas } as any);
jest.spyOn(ethRpcMethods, 'getGasPrice').mockReturnValueOnce(gasPrice as any);
jest.spyOn(ethRpcMethods, 'getMaxPriorityFeePerGas').mockReturnValueOnce(
maxPriorityFeePerGas as any,
);

const feeData = await web3Eth.calculateFeeData(); // no baseFeePerGasFactor passed
const defaultBaseFeePerGasFactor = BigInt(2);
expect(feeData).toMatchObject({
gasPrice,
maxFeePerGas: baseFeePerGas * defaultBaseFeePerGasFactor + maxPriorityFeePerGas,
maxPriorityFeePerGas,
baseFeePerGas,
});
});
});

1 comment on commit 69d83e7

@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: 69d83e7 Previous: efac906 Ratio
processingTx 22353 ops/sec (±7.82%) 23741 ops/sec (±5.98%) 1.06
processingContractDeploy 37636 ops/sec (±7.55%) 39369 ops/sec (±11.37%) 1.05
processingContractMethodSend 15415 ops/sec (±6.99%) 17405 ops/sec (±6.68%) 1.13
processingContractMethodCall 28129 ops/sec (±6.61%) 28770 ops/sec (±6.60%) 1.02
abiEncode 42413 ops/sec (±7.80%) 44377 ops/sec (±8.86%) 1.05
abiDecode 30494 ops/sec (±7.44%) 31118 ops/sec (±7.50%) 1.02
sign 1487 ops/sec (±3.26%) 1604 ops/sec (±0.56%) 1.08
verify 364 ops/sec (±0.46%) 369 ops/sec (±2.79%) 1.01

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

Please # to comment.