Skip to content

feat(deposit): quote the deposit fee the backend charges for each route - #2599

Merged
MayankMittal1 merged 3 commits into
masterfrom
mayank/feat/deposit-fee-from-backend
Sep 28, 2026
Merged

MayankMittal1 merged 3 commits into
masterfrom
mayank/feat/deposit-fee-from-backend

Conversation

@MayankMittal1

@MayankMittal1 MayankMittal1 commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The deposit address screens ("Fund your card", wallet deposit, savings deposit) showed a flat 0.03% fee everywhere. When an admin sets a different rate for a route and chain on the Deposit fees page, the backend charges that rate, but the app kept saying 0.03%.

The fee notice now asks GET /deposit/fee-quote for the rate. That endpoint runs the same assess() the deposit workflows charge with, so the app shows what will actually be taken.

Backend: no change needed. DepositFeeRateService.getRate already falls back to 300 ppm (0.03%) for a route and chain with no rate of its own, and on a failed read with nothing cached. deposit-fee-rate.service.spec.ts covers both.

How it works

  • getDepositFeeRatePpm (was getDepositFeeBps) keeps the existing route table. It now only decides which deposits can be charged. A deposit that is free by rule never calls the backend and never shows a fee, whatever the grid says.
  • For a deposit that can be charged, the notice shows the backend's ratePpm, or nothing when applies is false (a route set to 0%, the fee switched off, no treasury).
  • While the quote loads the line is left off. If the request fails, the notice falls back to 0.03% rather than to free.
  • Card and wallet deposits are quoted on RAIN_CARD, which the backend resolves to the Rain or Wirex card route. Savings deposits are quoted on PROTOCOL. The savings screen now passes the currency, which the quote needs.
  • Rates are in ppm, as the backend sends them, and are formatted with integer math, so 250 ppm prints 0.025%.
  • Answers are cached for 30s, the backend's own cache window for the rate grid.

Behaviour changes

  • The fee line now appears once the quote returns instead of at render time.
  • The line is now hidden when the backend would not charge the deposit. Before this change it showed 0.03% even with the fee switched off.
  • A backend without /deposit/fee-quote makes the request fail, so the app falls back to 0.03%, which is the same as today.

Also in this PR

  • Withdraw precision (RegularWithdrawForm, useVault): soETH and soFUSE balances are now kept in wei. A JS number can't hold 18 decimals, so a balance of 0.361164894291325699 became 0.3611648942913257. Max filled in that number, it passed validation, and the withdrawal reverted because it asked for more than the Safe holds. useSoFuseVaultBalance and useSoEthVaultBalance now return wei; RegularWithdrawForm is their only caller.
  • Assets (lib/assets.ts): registers the rewards-tier upgrade card SVGs and the credit-notice badge and background. All six files are already tracked.

Test plan

  • npx jest lib/utils/__tests__/depositFee.test.ts: 39 passed
  • npx jest components/DepositOption/__tests__/DepositFeeNotice.test.tsx: 11 passed
  • eslint on changed files; tsc --noEmit shows no errors in changed files
  • Withdraw max soETH and soFUSE from a Safe whose balance uses all 18 decimals; the withdrawal should go through
  • Set a custom rate for one route and chain on the admin Deposit fees page and check the matching deposit screen shows it within about 30s

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

The deposit address screens quoted a flat 0.03% everywhere, so a rate an
admin set for one route and chain on the Deposit fees page never reached
the app. The notice now asks /deposit/fee-quote, which runs the same
assessment the deposit workflows charge with and answers 0.03% for any
route and chain with no rate of its own.

The client's route table still decides which deposits can be charged at
all, so an address that is never bridged is never asked about. While the
quote loads the line is left off; if it cannot be fetched the notice
falls back to 0.03% rather than to free. Rates move to parts per million,
as the backend quotes them, so a fractional basis point prints exactly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated
solid-app Ignored Ignored Preview Sep 28, 2026 1:39pm UTC
solid-app-staging Ignored Ignored Preview Sep 28, 2026 1:39pm UTC

Request Review

MayankMittal1 and others added 2 commits September 28, 2026 19:09
…dation

A JS number cannot hold 18 decimals, so a soETH balance of
0.361164894291325699 became 0.3611648942913257. Max filled that in, it
passed the balance check, and the withdrawal reverted for asking more than
the Safe holds. The soFUSE and soETH balance hooks now return wei, and the
form validates and fills max in wei.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ce images

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Sep 28, 2026

Copy link
Copy Markdown

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@MayankMittal1
MayankMittal1 merged commit 216f4c1 into master Sep 28, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant