[LWDM] fix(LIVE-24415): align wallet quote network fees#17696
[LWDM] fix(LIVE-24415): align wallet quote network fees#17696philipptpunkt wants to merge 1 commit into
Conversation
|
Web Tools Build Status
|
There was a problem hiding this comment.
Pull request overview
Aligns wallet-quoted network fee handling across normalization, formatting, and sorting by introducing a single “total” network-fee amount and improving fee-estimation fallbacks (notably for BTC and non-EVM cases). This keeps quote ranking/formatting consistent with the fee that users actually see.
Changes:
- Replaces separate “estimated + approval” fee typing with
QuoteNetworkFeeAmountand addstotalNetworkFeetoQuoteDetails, then updates formatting/sorting to use the total. - Enhances fee normalization: preserves provider
networkFees.value, adds a provider-fee fallback when bridge-estimated fees are zero, and plumbstotalNetworkFeethrough quote details + formatted output. - Improves fee-context estimation: uses
fastfee strategy for Bitcoin and prevents tiny sampled amounts from rounding down to zero.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/types.ts | Updates re-exported quote types to use QuoteNetworkFeeAmount. |
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/sorting/sortQuotes.test.ts | Updates sorting test expectations to reflect “total network fee” usage. |
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/sorting/buildNetCounterValue.ts | Net countervalue now subtracts totalNetworkFee countervalue (instead of summing parts). |
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/normalizer/normalizeQuote.ts | Adjusts formatted plumbing to no longer pass feeEstimate into formatting. |
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/normalizer/normalizeQuote.test.ts | Adds/updates tests for totalNetworkFee, preserved provider fees, and formatted totals. |
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/normalizer/networkFees.ts | Preserves provider-reported networkFees.value into normalized quote details. |
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/normalizer/networkFeeEstimate.ts | Introduces provider-fee fallback when bridge estimate is zero; updates fee amount typing. |
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/normalizer/networkFeeEstimate.test.ts | Adds coverage for the new provider-fee fallback behavior. |
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/normalizer/buildQuoteDetails.ts | Computes and stores totalNetworkFee derived from estimated + approval components. |
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/normalizer/buildFormattedQuoteValues.ts | Formats/display-network-fee based on totalNetworkFee and uses its currency id for countervalue. |
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/fetchNetworkFeeContext.ts | Uses BTC fast fee strategy and ensures sampled amounts remain non-zero after rounding. |
| libs/ledger-live-common/src/wallet-api/Exchange/quotes/fetchNetworkFeeContext.test.ts | Adds assertions for BTC fee strategy and non-zero rounding behavior. |
| libs/exchange-module/src/types.ts | Updates public exchange-module types: introduces QuoteNetworkFeeAmount and adds totalNetworkFee. |
| amount: string; | ||
| currencyId: string; | ||
| }; | ||
|
|
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; | ||
|
|
Rsdoctor Bundle Diff AnalysisFound 7 projects in monorepo, 7 projects with changes. 📊 Quick Summary
📋 Detailed Reports (Click to expand)📁 desktop-mainPath:
📁 desktop-preloaderPath:
📁 desktop-rendererPath:
📁 desktop-webviewDappPreloaderPath:
📁 desktop-webviewPreloaderPath:
📁 mobilePath:
📁 desktop-workersPath:
Generated by Rsdoctor GitHub Action |
6be31b8 to
ef6d571
Compare
022d4f6 to
d4ad73e
Compare
ef6d571 to
a3efa26
Compare
d4ad73e to
3bfc36b
Compare
| /** | ||
| * Wallet-computed network-fee estimate for the default fee strategy. | ||
| * `amount` is in atomic units as a decimal string to preserve precision for | ||
| * chains whose fees exceed `Number.MAX_SAFE_INTEGER`. | ||
| * Network fee amount in atomic units as a decimal string. | ||
| */ | ||
| export type QuoteEstimatedNetworkFee = { | ||
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; |
| QuotePermitData, | ||
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; |
a3efa26 to
6f0f4a6
Compare
3bfc36b to
7577e8d
Compare
6f0f4a6 to
8b841d0
Compare
2a2409f to
65b9551
Compare
1c35d69 to
8e51285
Compare
65b9551 to
c1f12d1
Compare
| QuoteLiquiditySource, | ||
| QuotePayoutNetworkFees, | ||
| QuotePermit2Message, | ||
| QuotePermitData, | ||
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; | ||
|
|
| QuotePermit2Message, | ||
| QuotePermitData, | ||
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; |
| const higherReceiveWithFees = makeQuote("higher-receive-with-fees", { | ||
| receiveAmount: 1, | ||
| estimatedNetworkFee: { amount: "100000000000000000", currencyId: "ethereum" }, | ||
| approvalNetworkFee: { amount: "100000000000000000", currencyId: "ethereum" }, | ||
| totalNetworkFee: { amount: "200000000000000000", currencyId: "ethereum" }, | ||
| }); |
| networkFeesCurrencyId: | ||
| quoteDetails.totalNetworkFee?.currencyId ?? quoteDetails.networkFees.currencyId, | ||
| }, |
| networkFeesCurrencyId: | ||
| quoteDetails.totalNetworkFee?.currencyId ?? quoteDetails.networkFees.currencyId, | ||
| }, |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, |
| const networkFee = feeAmountAsDisplayValue( | ||
| quote.quoteDetails.totalNetworkFee, | ||
| context.feeCurrencyMagnitude, | ||
| ); | ||
| const feeCurrencyId = |
| const providerFee = new BigNumber(quote.networkFees.value ?? 0); | ||
| if (!providerFee.gt(0)) { | ||
| return context.estimatedFeesAtomic; | ||
| } | ||
|
|
||
| return providerFee.shiftedBy(context.feeCurrencyMagnitude).integerValue(BigNumber.ROUND_DOWN); |
| /** | ||
| * Wallet-computed network-fee estimate for the default fee strategy. | ||
| * Wallet-computed network-fee amount. | ||
| * `amount` is in atomic units as a decimal string to preserve precision for | ||
| * chains whose fees exceed `Number.MAX_SAFE_INTEGER`. | ||
| */ | ||
| export type QuoteEstimatedNetworkFee = { | ||
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| QuotePermit2Message, | ||
| QuotePermitData, | ||
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; |
| /** | ||
| * Wallet-computed network-fee estimate for the default fee strategy. | ||
| * Wallet-computed network-fee amount. | ||
| * `amount` is in atomic units as a decimal string to preserve precision for | ||
| * chains whose fees exceed `Number.MAX_SAFE_INTEGER`. | ||
| */ | ||
| export type QuoteEstimatedNetworkFee = { | ||
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| QuotePermit2Message, | ||
| QuotePermitData, | ||
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; |
| networkFeesCurrencyId: | ||
| quoteDetails.totalNetworkFee?.currencyId ?? quoteDetails.networkFees.currencyId, |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| QuotePermitData, | ||
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| estimatedNetworkFee?: QuoteNetworkFeeAmount; | ||
| approvalNetworkFee?: QuoteNetworkFeeAmount; | ||
| totalNetworkFee?: QuoteNetworkFeeAmount; |
| networkFeesCurrencyId: | ||
| quoteDetails.totalNetworkFee?.currencyId ?? quoteDetails.networkFees.currencyId, |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; |
| @@ -344,8 +338,9 @@ export type QuoteDetails = { | |||
| tokenAllowance?: QuoteTokenAllowance; | |||
| tags?: QuoteTags; | |||
| permitData?: QuotePermitData; | |||
| estimatedNetworkFee?: QuoteEstimatedNetworkFee; | |||
| approvalNetworkFee?: QuoteApprovalNetworkFee; | |||
| estimatedNetworkFee?: QuoteNetworkFeeAmount; | |||
| approvalNetworkFee?: QuoteNetworkFeeAmount; | |||
| totalNetworkFee?: QuoteNetworkFeeAmount; | |||
| }; | |||
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, |
| const networkFee = feeAmountAsDisplayValue( | ||
| quote.quoteDetails.totalNetworkFee, | ||
| context.feeCurrencyMagnitude, | ||
| ); | ||
| const feeCurrencyId = | ||
| quote.quoteDetails.estimatedNetworkFee?.currencyId ?? | ||
| quote.quoteDetails.approvalNetworkFee?.currencyId ?? | ||
| quote.quoteDetails.networkFees.currencyId; | ||
| quote.quoteDetails.totalNetworkFee?.currencyId ?? quote.quoteDetails.networkFees.currencyId; | ||
| const feeSpotPrice = context.spotPrices[feeCurrencyId] || 0; |
| return context.estimatedFeesAtomic; | ||
| } | ||
|
|
||
| const providerFee = new BigNumber(quote.networkFees.value ?? 0); |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| /** | ||
| * Wallet-computed network-fee estimate for the default fee strategy. | ||
| * Wallet-computed network-fee amount. | ||
| * `amount` is in atomic units as a decimal string to preserve precision for | ||
| * chains whose fees exceed `Number.MAX_SAFE_INTEGER`. | ||
| */ | ||
| export type QuoteEstimatedNetworkFee = { | ||
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| QuotePermit2Message, | ||
| QuotePermitData, | ||
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, |
| const higherReceiveWithFees = makeQuote("higher-receive-with-fees", { | ||
| receiveAmount: 1, | ||
| estimatedNetworkFee: { amount: "100000000000000000", currencyId: "ethereum" }, | ||
| approvalNetworkFee: { amount: "100000000000000000", currencyId: "ethereum" }, | ||
| totalNetworkFee: { amount: "200000000000000000", currencyId: "ethereum" }, | ||
| }); |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; | ||
|
|
| function resolveFeeStrategy(account: Account): "fast" | "medium" { | ||
| return account.currency.id === "bitcoin" ? "fast" : "medium"; | ||
| } |
| * Wallet-computed network-fee amount. | ||
| * `amount` is in atomic units as a decimal string to preserve precision for | ||
| * chains whose fees exceed `Number.MAX_SAFE_INTEGER`. | ||
| */ | ||
| export type QuoteEstimatedNetworkFee = { | ||
| export type QuoteNetworkFeeAmount = { |
| QuotePermitData, | ||
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; |
| estimatedNetworkFee?: QuoteNetworkFeeAmount; | ||
| approvalNetworkFee?: QuoteNetworkFeeAmount; | ||
| totalNetworkFee?: QuoteNetworkFeeAmount; | ||
| }; |
| /** | ||
| * Wallet-computed network-fee estimate for the default fee strategy. | ||
| * Wallet-computed network-fee amount. | ||
| * `amount` is in atomic units as a decimal string to preserve precision for | ||
| * chains whose fees exceed `Number.MAX_SAFE_INTEGER`. | ||
| */ | ||
| export type QuoteEstimatedNetworkFee = { | ||
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| QuotePermitData, | ||
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, | ||
| } from "@ledgerhq/wallet-api-exchange-module"; |
| return context.estimatedFeesAtomic; | ||
| } | ||
|
|
||
| const providerFee = new BigNumber(quote.networkFees.value ?? 0); |
| export type QuoteNetworkFeeAmount = { | ||
| amount: string; | ||
| currencyId: string; | ||
| }; |
| QuotePermit2Message, | ||
| QuotePermitData, | ||
| QuoteTags, | ||
| QuoteTokenAllowance, | ||
| QuoteEstimatedNetworkFee, | ||
| QuoteApprovalNetworkFee, | ||
| QuoteNetworkFeeAmount, |
| receiveAmount: 1, | ||
| estimatedNetworkFee: { amount: "100000000000000000", currencyId: "ethereum" }, | ||
| approvalNetworkFee: { amount: "100000000000000000", currencyId: "ethereum" }, | ||
| totalNetworkFee: { amount: "200000000000000000", currencyId: "ethereum" }, |
|



Stack (managed by stac-man)