Skip to content

fix(tokens): fall back to the house sell fee on the buy leg - #1305

Merged
bmc08gt merged 1 commit into
code/cashfrom
fix/buy-fee-bps-fallback
Aug 22, 2026
Merged

fix(tokens): fall back to the house sell fee on the buy leg#1305
bmc08gt merged 1 commit into
code/cashfrom
fix/buy-fee-bps-fallback

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

Came out of an iOS↔Android diff of the fee-affordable entry correction (#1302 here, code-ios-app#625 there). The pure math and the unit suites match case-for-case; this was the one behavioral difference.

The bug

A launchpad token whose metadata omits sellFeeBps was treated as fee-free when it funded a buy — in two places that have to agree:

  • SwapViewModel.buyFeeFor — the bps used to trim the entry down to what the balance can afford
  • the gross-up in OnBuyConfirmed — the bps folded into the debit at confirm time

Both fell back to 0. The convert leg (convertFeeBps) already falls back to the house rate for exactly the same case, so the two legs priced the same token differently, and iOS assumes the house rate on every leg (sellFeeBps ?? 100 in BuyAmountViewModel, BuyConfirmationViewModel).

Why the house rate is the right fallback

The fee is grossed up into the debit. Under-estimating it prices a debit the funding balance can't actually cover, so the entry is never trimmed and the swap fails downstream instead. Over-estimating only trims the entry slightly harder. Erring high is the safe direction.

The change

HOUSE_SELL_FEE_BPS now lives once next to the rest of the fee math in LaunchpadSellFee.kt, with LaunchpadMetadata?.sellFeeBpsOrHouseRate reading it off a pool. The buy leg, the convert leg, and the on-top Dollars rate all resolve through it, so they can't drift apart again. DEFAULT_CONVERT_FEE_BPS keeps its name and now aliases the shared constant — no behavior change on the USDF paths.

Tests added to LaunchpadSellFeeTest for both sides of the fallback.

A launchpad token whose metadata omits `sellFeeBps` was treated as fee-free
when it funded a buy — both when trimming the entry to what the balance can
afford and when grossing the fee up into the debit at confirm time. The
convert leg already falls back to the house rate for the same case, so the
two legs disagreed about the same token, and iOS assumes the house rate on
every leg.

Erring high is the safe direction here: the fee is grossed up into the
debit, so a zero fallback prices a debit the funding balance can't actually
cover, and the swap fails downstream rather than being trimmed up front.

Names the fallback once as `HOUSE_SELL_FEE_BPS` next to the rest of the
fee math, with `sellFeeBpsOrHouseRate` reading it off a pool, so the buy
leg, the convert leg, and the on-top Dollars rate can't drift apart again.
@github-actions github-actions Bot added area: network gRPC, connectivity, API, exchange rates area: tokens Token accounts, balances, token info type: fix Bug fix labels Aug 22, 2026
@bmc08gt
bmc08gt merged commit 60403f7 into code/cash Aug 22, 2026
3 checks passed
@bmc08gt
bmc08gt deleted the fix/buy-fee-bps-fallback branch August 22, 2026 01:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: network gRPC, connectivity, API, exchange rates area: tokens Token accounts, balances, token info type: fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant