From 26b2527b68b1e4cf402599e68f363470b217ad6a Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Tue, 9 Jan 2024 11:49:28 +0100 Subject: [PATCH 1/3] feat(ethereum-storage): gas fee multiplier & max gas fee --- .../src/ethereum-tx-submitter.ts | 20 ++++++++++++-- .../ethereum-storage/src/gas-fee-definer.ts | 16 +++++++++--- packages/utils/src/normalize-gas-fees.ts | 17 +++++++++--- .../utils/test/normalize-gas-fees.test.ts | 26 +++++++++++++++++++ 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/packages/ethereum-storage/src/ethereum-tx-submitter.ts b/packages/ethereum-storage/src/ethereum-tx-submitter.ts index e8625cbd0a..8d66b0bcd6 100644 --- a/packages/ethereum-storage/src/ethereum-tx-submitter.ts +++ b/packages/ethereum-storage/src/ethereum-tx-submitter.ts @@ -8,6 +8,8 @@ import { SimpleLogger, isEip1559Supported } from '@requestnetwork/utils'; export type SubmitterProps = { signer: Signer; gasPriceMin?: BigNumber; + gasPriceMax?: BigNumber; + gasPriceMultiplier?: number; network: CurrencyTypes.EvmChainName; logger?: LogTypes.ILogger; debugProvider?: boolean; @@ -23,7 +25,15 @@ export class EthereumTransactionSubmitter implements StorageTypes.ITransactionSu private readonly provider: providers.JsonRpcProvider; private readonly gasFeeDefiner: GasFeeDefiner; - constructor({ network, signer, logger, gasPriceMin, debugProvider }: SubmitterProps) { + constructor({ + network, + signer, + logger, + gasPriceMin, + gasPriceMax, + gasPriceMultiplier, + debugProvider, + }: SubmitterProps) { this.logger = logger || new SimpleLogger(); const provider = signer.provider as providers.JsonRpcProvider; this.provider = provider; @@ -31,7 +41,13 @@ export class EthereumTransactionSubmitter implements StorageTypes.ITransactionSu network, signer, ) as RequestOpenHashSubmitter; // type mismatch with ethers. - this.gasFeeDefiner = new GasFeeDefiner({ provider, gasPriceMin, logger: this.logger }); + this.gasFeeDefiner = new GasFeeDefiner({ + provider, + gasPriceMin, + gasPriceMax, + gasPriceMultiplier, + logger: this.logger, + }); if (debugProvider) { this.provider.on('debug', (event) => { this.logger.debug('JsonRpcProvider debug event', event); diff --git a/packages/ethereum-storage/src/gas-fee-definer.ts b/packages/ethereum-storage/src/gas-fee-definer.ts index 7cdf857b4f..7515fea149 100644 --- a/packages/ethereum-storage/src/gas-fee-definer.ts +++ b/packages/ethereum-storage/src/gas-fee-definer.ts @@ -1,31 +1,41 @@ import { suggestFees } from '@rainbow-me/fee-suggestions'; -import { BigNumber, providers, constants } from 'ethers'; +import { BigNumber, providers } from 'ethers'; import { normalizeGasFees } from '@requestnetwork/utils'; import { FeeTypes, LogTypes } from '@requestnetwork/types'; export class GasFeeDefiner { private readonly logger: LogTypes.ILogger; private readonly provider: providers.JsonRpcProvider; - private readonly gasPriceMin: BigNumber; + private readonly gasPriceMin?: BigNumber; + private readonly gasPriceMax?: BigNumber; + private readonly gasPriceMultiplier?: number; constructor({ logger, provider, gasPriceMin, + gasPriceMax, + gasPriceMultiplier, }: { logger: LogTypes.ILogger; gasPriceMin?: BigNumber; + gasPriceMax?: BigNumber; + gasPriceMultiplier?: number; provider: providers.JsonRpcProvider; }) { this.logger = logger; this.provider = provider; - this.gasPriceMin = gasPriceMin || constants.Zero; + this.gasPriceMin = gasPriceMin; + this.gasPriceMax = gasPriceMax; + this.gasPriceMultiplier = gasPriceMultiplier; } public async getGasFees(): Promise { return normalizeGasFees({ logger: this.logger, gasPriceMin: this.gasPriceMin, + gasPriceMax: this.gasPriceMax, + gasPriceMultiplier: this.gasPriceMultiplier, suggestFees: async () => { const { baseFeeSuggestion, maxPriorityFeeSuggestions } = await suggestFees(this.provider); return { diff --git a/packages/utils/src/normalize-gas-fees.ts b/packages/utils/src/normalize-gas-fees.ts index 24a6c960b6..aeaf64ad15 100644 --- a/packages/utils/src/normalize-gas-fees.ts +++ b/packages/utils/src/normalize-gas-fees.ts @@ -1,6 +1,6 @@ import { BigNumber, constants } from 'ethers'; -import { maxBigNumber } from './index'; +import { maxBigNumber, minBigNumber } from './index'; import { LogTypes, FeeTypes } from '@requestnetwork/types'; /** @@ -14,22 +14,31 @@ import { LogTypes, FeeTypes } from '@requestnetwork/types'; async function normalizeGasFees({ logger, gasPriceMin, + gasPriceMax, + gasPriceMultiplier, suggestFees, }: { logger: LogTypes.ILogger; gasPriceMin?: BigNumber; + gasPriceMax?: BigNumber; + gasPriceMultiplier?: number; suggestFees: () => Promise; }): Promise { try { const suggestedFee = await suggestFees(); - const baseFee = maxBigNumber(suggestedFee.baseFee, gasPriceMin || constants.Zero); - const maxPriorityFeePerGas = maxBigNumber( suggestedFee.maxPriorityFee, gasPriceMin || constants.Zero, ); - const maxFeePerGas = baseFee.add(maxPriorityFeePerGas); + + const maxFeePerGasInit = baseFee + .add(maxPriorityFeePerGas) + .mul(gasPriceMultiplier || 100) + .div(100); + const maxFeePerGas = gasPriceMax + ? minBigNumber(maxFeePerGasInit, gasPriceMax) + : maxFeePerGasInit; if (maxPriorityFeePerGas.eq(0) || maxFeePerGas.eq(0)) { logger.warn( diff --git a/packages/utils/test/normalize-gas-fees.test.ts b/packages/utils/test/normalize-gas-fees.test.ts index 72d63a002c..67ff97fe8f 100644 --- a/packages/utils/test/normalize-gas-fees.test.ts +++ b/packages/utils/test/normalize-gas-fees.test.ts @@ -18,4 +18,30 @@ describe('Normalize Gas Fees', () => { expect(normalizedGasFees.maxPriorityFeePerGas?.toString()).toBe('1000000000'); expect(normalizedGasFees.maxFeePerGas?.toString()).toBe('2000000000'); }); + + it('should respect maximum gas fee', async () => { + const normalizedGasFees = await normalizeGasFees({ + logger: console, + suggestFees: async () => ({ + baseFee: '400000000000', // 400 Gwei + maxPriorityFee: '2000000000', // 2 Gwei + }), + gasPriceMax: BigNumber.from('250000000000'), // 250 Gwei + }); + expect(normalizedGasFees.maxPriorityFeePerGas?.toString()).toBe('2000000000'); // 2 Gwei + expect(normalizedGasFees.maxFeePerGas?.toString()).toBe('250000000000'); // 250 Gwei + }); + + it('should respect gas multiplier', async () => { + const normalizedGasFees = await normalizeGasFees({ + logger: console, + suggestFees: async () => ({ + baseFee: '20000000000', // 20 Gwei + maxPriorityFee: '2000000000', // 2 Gwei + }), + gasPriceMultiplier: 200, // x2 + }); + expect(normalizedGasFees.maxPriorityFeePerGas?.toString()).toBe('2000000000'); // 2 Gwei + expect(normalizedGasFees.maxFeePerGas?.toString()).toBe('44000000000'); // (20 + 2) x 2 = 44 Gwei + }); }); From 412b1c732d487faca50a0a1060d90c6cfde2f31f Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Wed, 10 Jan 2024 16:31:07 +0100 Subject: [PATCH 2/3] add comments --- .../ethereum-storage/src/ethereum-tx-submitter.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/ethereum-storage/src/ethereum-tx-submitter.ts b/packages/ethereum-storage/src/ethereum-tx-submitter.ts index 8d66b0bcd6..e61b75ae7b 100644 --- a/packages/ethereum-storage/src/ethereum-tx-submitter.ts +++ b/packages/ethereum-storage/src/ethereum-tx-submitter.ts @@ -7,8 +7,20 @@ import { SimpleLogger, isEip1559Supported } from '@requestnetwork/utils'; export type SubmitterProps = { signer: Signer; + /** + * The minimum value for maxPriorityFeePerGas and maxFeePerGas + * The default is zero. + */ gasPriceMin?: BigNumber; + /** + * The maximum value for maxFeePerGas. + * There is no limit if no value is set. + */ gasPriceMax?: BigNumber; + /** + * A multiplier for the computed maxFeePerGas. + * The default is 100, which does not change the value (100 is equal to x1, 200 is equal to x2). + */ gasPriceMultiplier?: number; network: CurrencyTypes.EvmChainName; logger?: LogTypes.ILogger; From 32498c0896fce935e7e62e2d439d98e582171f0d Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Wed, 10 Jan 2024 16:54:59 +0100 Subject: [PATCH 3/3] add comments --- packages/ethereum-storage/src/ethereum-tx-submitter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ethereum-storage/src/ethereum-tx-submitter.ts b/packages/ethereum-storage/src/ethereum-tx-submitter.ts index e61b75ae7b..3fdacbc702 100644 --- a/packages/ethereum-storage/src/ethereum-tx-submitter.ts +++ b/packages/ethereum-storage/src/ethereum-tx-submitter.ts @@ -8,7 +8,7 @@ import { SimpleLogger, isEip1559Supported } from '@requestnetwork/utils'; export type SubmitterProps = { signer: Signer; /** - * The minimum value for maxPriorityFeePerGas and maxFeePerGas + * The minimum value for maxPriorityFeePerGas and maxFeePerGas. * The default is zero. */ gasPriceMin?: BigNumber;