Skip to content

feat(frontend): live wallet balances and safe maximum stake calculation - #577

Merged
PeterOche merged 1 commit into
degenspot:mainfrom
feyishola:feat/wallet-balances-max-stake-552
Aug 28, 2026
Merged

feat(frontend): live wallet balances and safe maximum stake calculation#577
PeterOche merged 1 commit into
degenspot:mainfrom
feyishola:feat/wallet-balances-max-stake-552

Conversation

@feyishola

@feyishola feyishola commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

StakingInterface derived its 25/50/75/MAX presets from a hard-coded BALANCE = 1000, so a user could select an amount unrelated to the connected wallet and only discover the problem when the transaction failed. The screen also could not tell an insufficient token balance apart from a missing trustline or from not holding enough XLM to pay the fee.

Add src/lib/stellar and the useWalletBalances hook as the single source of truth for how much a wallet can actually stake:

  • the stake asset is identified by asset code AND issuer (or the SAC contract ID), never by symbol, so a same-ticker impostor asset is not counted as a balance and a market denominated in another asset blocks staking outright;
  • spendable is narrower than balance: the base reserve, selling liabilities and, when staking XLM, a fee buffer all come off the top, so MAX cannot produce a transaction the network is certain to reject;
  • MAX and the percentage presets are clamped to the contract's min_stake / max_stake_per_user;
  • every amount stays a bigint of stroops, preserving Stellar's 7 decimals; the amount field is now editable so an exact amount can be entered, and formatting happens only at display.

Horizon's three outcomes are modelled explicitly (ok, not-found, unavailable) so an unreachable RPC is shown as stale data rather than silently read as a zero balance. The panel renders a distinct state for disconnected wallet, unfunded account, missing/unauthorized trustline, stale response, zero balance and insufficient fee balance, each with a recovery action.

Reads are keyed by network|address: concurrent consumers and the post-stake refresh join one in-flight request, and a reply that lands after the wallet changed is discarded rather than attributed to the new address.

Covered by 75 unit tests over decimal conversion, MAX/percent maths and snapshot derivation, 12 hook tests over refresh and de-duplication, and 24 component tests over each disabled/error state.

closes #576

StakingInterface derived its 25/50/75/MAX presets from a hard-coded
BALANCE = 1000, so a user could select an amount unrelated to the
connected wallet and only discover the problem when the transaction
failed. The screen also could not tell an insufficient token balance
apart from a missing trustline or from not holding enough XLM to pay
the fee.

Add src/lib/stellar and the useWalletBalances hook as the single source
of truth for how much a wallet can actually stake:

- the stake asset is identified by asset code AND issuer (or the SAC
  contract ID), never by symbol, so a same-ticker impostor asset is not
  counted as a balance and a market denominated in another asset blocks
  staking outright;
- spendable is narrower than balance: the base reserve, selling
  liabilities and, when staking XLM, a fee buffer all come off the top,
  so MAX cannot produce a transaction the network is certain to reject;
- MAX and the percentage presets are clamped to the contract's
  min_stake / max_stake_per_user;
- every amount stays a bigint of stroops, preserving Stellar's 7
  decimals; the amount field is now editable so an exact amount can be
  entered, and formatting happens only at display.

Horizon's three outcomes are modelled explicitly (ok, not-found,
unavailable) so an unreachable RPC is shown as stale data rather than
silently read as a zero balance. The panel renders a distinct state for
disconnected wallet, unfunded account, missing/unauthorized trustline,
stale response, zero balance and insufficient fee balance, each with a
recovery action.

Reads are keyed by network|address: concurrent consumers and the
post-stake refresh join one in-flight request, and a reply that lands
after the wallet changed is discarded rather than attributed to the new
address.

Covered by 75 unit tests over decimal conversion, MAX/percent maths and
snapshot derivation, 12 hook tests over refresh and de-duplication, and
24 component tests over each disabled/error state.
@PeterOche
PeterOche merged commit 25c2798 into degenspot:main Aug 28, 2026
1 check 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.

Implement Wallet Asset Balances and Safe Maximum Stake Calculation

2 participants