From dc86dbe1a37374d49712742038804d7f8ab8a16a Mon Sep 17 00:00:00 2001 From: Albina Nikiforova Date: Thu, 16 Jan 2025 16:50:46 +0100 Subject: [PATCH] feat(suite): build priority fees levels --- .../blockchain-link-types/src/responses.ts | 21 ++++++++ packages/connect/src/api/bitcoin/Fees.ts | 53 ++++++++++++++----- packages/connect/src/types/fees.ts | 15 ++++++ .../src/blockchain/blockchainThunks.ts | 8 ++- 4 files changed, 80 insertions(+), 17 deletions(-) diff --git a/packages/blockchain-link-types/src/responses.ts b/packages/blockchain-link-types/src/responses.ts index aa96ef26489..f4693e2e5d4 100644 --- a/packages/blockchain-link-types/src/responses.ts +++ b/packages/blockchain-link-types/src/responses.ts @@ -98,6 +98,27 @@ export interface EstimateFee { feePerUnit: string; feePerTx?: string; feeLimit?: string; + eip1559?: { + baseFeePerGas: string; + low: { + maxFeePerGas: string; + maxPriorityFeePerGas: string; + minWaitTimeEstimate: number; + maxWaitTimeEstimate: number; + }; + medium: { + maxFeePerGas: string; + maxPriorityFeePerGas: string; + minWaitTimeEstimate: number; + maxWaitTimeEstimate: number; + }; + high: { + maxFeePerGas: string; + maxPriorityFeePerGas: string; + minWaitTimeEstimate: number; + maxWaitTimeEstimate: number; + }; + }; }[]; } diff --git a/packages/connect/src/api/bitcoin/Fees.ts b/packages/connect/src/api/bitcoin/Fees.ts index 1f41d03f33d..d427170a539 100644 --- a/packages/connect/src/api/bitcoin/Fees.ts +++ b/packages/connect/src/api/bitcoin/Fees.ts @@ -82,19 +82,48 @@ export class FeeLevels { async loadMisc(blockchain: Blockchain) { try { const [response] = await blockchain.estimateFee({ blocks: [1] }); + + if (response.eip1559) { + const eip1559LevelKeys = ['low', 'medium', 'high'] as const; + + const { eip1559, ...baseLevel } = response; + const eip1559Levels = eip1559LevelKeys.map(levelKey => { + const level = eip1559[levelKey]; + + return { + label: levelKey, + baseFeePerGas: eip1559.baseFeePerGas, + maxFeePerGas: level.maxFeePerGas, + maxPriorityFeePerGas: level.maxPriorityFeePerGas, + minWaitTimeEstimate: level.minWaitTimeEstimate, + maxWaitTimeEstimate: level.maxWaitTimeEstimate, + feePerUnit: '0', + feeLimit: undefined, + ethFeeType: 'eip1559' as const, + blocks: -1, + }; + }); + + this.levels = [ + { ...baseLevel, label: 'normal' as const, blocks: -1, ethFeeType: 'legacy' }, + ...eip1559Levels, + ]; + } else { + this.levels[0] = { + ...this.levels[0], + ...response, + // validate `feePerUnit` from the backend + // should be lower than `coinInfo.maxFee` and higher than `coinInfo.minFee` + // xrp sends values from 1 to very high number occasionally + // see: https://github.com/trezor/trezor-suite/blob/develop/packages/blockchain-link/src/workers/ripple/index.ts#L316 + feePerUnit: Math.min( + this.coinInfo.maxFee, + Math.max(this.coinInfo.minFee, parseInt(response.feePerUnit, 10)), + ).toString(), + }; + } + // misc coins should have only one FeeLevel (normal) - this.levels[0] = { - ...this.levels[0], - ...response, - // validate `feePerUnit` from the backend - // should be lower than `coinInfo.maxFee` and higher than `coinInfo.minFee` - // xrp sends values from 1 to very high number occasionally - // see: https://github.com/trezor/trezor-suite/blob/develop/packages/blockchain-link/src/workers/ripple/index.ts#L316 - feePerUnit: Math.min( - this.coinInfo.maxFee, - Math.max(this.coinInfo.minFee, parseInt(response.feePerUnit, 10)), - ).toString(), - }; } catch { // silent } diff --git a/packages/connect/src/types/fees.ts b/packages/connect/src/types/fees.ts index a23260ba08d..2d32cdf06d3 100644 --- a/packages/connect/src/types/fees.ts +++ b/packages/connect/src/types/fees.ts @@ -8,6 +8,14 @@ export const FeeInfo = Type.Object({ dustLimit: Type.Number(), }); +export type PriorityFeeEstimationDetails = Static; +export const PriorityFeeEstimationDetails = Type.Object({ + maxFeePerGas: Type.String(), + maxPriorityFeePerGas: Type.String(), + maxWaitTimeEstimate: Type.Number(), + minWaitTimeEstimate: Type.Number(), +}); + export type FeeLevel = Static; export const FeeLevel = Type.Object({ label: Type.Union([ @@ -16,11 +24,18 @@ export const FeeLevel = Type.Object({ Type.Literal('economy'), Type.Literal('low'), Type.Literal('custom'), + Type.Literal('medium'), ]), + ethFeeType: Type.Optional(Type.Union([Type.Literal('legacy'), Type.Literal('eip1559')])), feePerUnit: Type.String(), blocks: Type.Number(), feeLimit: Type.Optional(Type.String()), // eth gas limit feePerTx: Type.Optional(Type.String()), // fee for BlockchainEstimateFeeParams.request.specific + baseFeePerGas: Type.Optional(Type.String()), + maxFeePerGas: Type.Optional(Type.String()), + maxPriorityFeePerGas: Type.Optional(Type.String()), + maxWaitTimeEstimate: Type.Optional(Type.Number()), + minWaitTimeEstimate: Type.Optional(Type.Number()), }); export type SelectFeeLevel = Static; diff --git a/suite-common/wallet-core/src/blockchain/blockchainThunks.ts b/suite-common/wallet-core/src/blockchain/blockchainThunks.ts index 62ac596fa04..288b6b99257 100644 --- a/suite-common/wallet-core/src/blockchain/blockchainThunks.ts +++ b/suite-common/wallet-core/src/blockchain/blockchainThunks.ts @@ -58,7 +58,7 @@ const getAccountSyncInterval = (symbol: NetworkSymbol) => // sort FeeLevels in reversed order (Low > High) // TODO: consider to use same order in @trezor/connect to avoid double sorting -const order: FeeLevel['label'][] = ['low', 'economy', 'normal', 'high']; +const order: FeeLevel['label'][] = ['low', 'economy', 'medium', 'normal', 'high']; const sortLevels = (levels: FeeLevel[]) => levels.sort((levelA, levelB) => order.indexOf(levelA.label) - order.indexOf(levelB.label)); @@ -124,13 +124,11 @@ export const updateFeeInfoThunk = createThunk( let newFeeInfo; if (network.networkType === 'ethereum') { - // NOTE: ethereum smart fees are not implemented properly in @trezor/connect Issue: https://github.com/trezor/trezor-suite/issues/5340 - // create raw call to @trezor/blockchain-link, receive data and create FeeLevel.normal from it - const result = await TrezorConnect.blockchainEstimateFee({ coin: network.symbol, request: { blocks: [2], + feeLevels: 'smart', specific: { from: '0x0000000000000000000000000000000000000000', to: '0x0000000000000000000000000000000000000000', @@ -143,7 +141,7 @@ export const updateFeeInfoThunk = createThunk( levels: result.payload.levels.map(l => ({ ...l, blocks: -1, // NOTE: @trezor/connect returns -1 for ethereum default - label: 'normal' as const, + label: l.label || ('normal' as const), })), }; }