Skip to content

Read vault and wallet USDC balances from Soroban instead of hardcoded values #1313

Description

@greatest0fallt1me

Summary

The balances users base funding decisions on are made up. The Billing page, the deposit modal and the Dashboard all show a vault balance of 284.62 and a wallet balance of 1260.5 USDC whatever the chain says. After a deposit, the UI adds the amount locally instead of reading the new balance back. This issue reads both balances from Stellar testnet through read-only Soroban simulation, and makes loading, error and stale states explicit.

Background and evidence

  • src/App.tsx line 354 sets useState(284.62) for vaultBalance, and line 355 sets useState(1260.5) for walletBalance.
  • These values feed:
    • the Billing vault cards (lines 692–704)
    • the modal balance tiles (lines 899–908)
    • the Max button (handleMax, line 532)
    • the "exceeds wallet balance" validation (line 434)
    • DashboardPage (line 664)
  • After a confirmed deposit, line 578 sets the balance to startingBalance + approvedAmount, which is an optimistic local sum that is never reconciled with the chain.
  • src/pages/DashboardOverview.tsx line 94 hardcodes the subtitle "Freighter Stellar Wallet (Public Net)" even though the app targets testnet.
  • The contract interface (Callora-Contracts contracts/vault/src/lib.rs):
    • balance() (line 1231) returns the tracked vault balance in stroops (7 decimals).
    • get_usdc_token() (line 1261) returns the USDC SAC address. On testnet this is CAC7CFZ42L3LTTZCI4C3XI6UF7AHS2PYTNJ5QEG2PSLRGDGMWRQOZOT5 (docs/DEPLOYMENTS.md).
    • The SAC's balance(id) gives the wallet's USDC balance.

Scope

In scope

  1. New module src/services/vaultReads.ts with:
    • readVaultBalance(): Promise<bigint>, which simulates balance() on STELLAR_VAULT_CONTRACT_ID.
    • readUsdcToken(): Promise<string>, which simulates get_usdc_token() and caches the result for the session.
    • readWalletUsdcBalance(address): Promise<bigint>, which simulates SAC balance(address).
    • All three use scValToNative, and stroops stay as bigint until formatting.
  2. Hook useVaultBalances() returning { vault, wallet, status: "idle" | "loading" | "ready" | "error", error, refresh, updatedAt }.
    • The wallet read only runs once a Freighter address is known.
    • Requests are aborted or ignored when they are superseded.
  3. Replace the hardcoded state in App.tsx with the hook.
    • Billing cards, modal tiles, Max and validation use real values.
    • While loading, show skeletons that do not shift layout.
    • On error, show an inline message with a Retry button, and never show 0 as if it were real.
  4. Read back after deposit. After submitVaultDeposit resolves, call refresh() and show the chain value. Use the optimistic value only as a labelled "pending refresh" placeholder until the read returns.
  5. Dashboard. Pass the same values to DashboardPage and correct the network label using STELLAR_NETWORK.

Out of scope

  • Billing history, deposit preflight and trustline handling (separate issues).
  • Backend /api/vault/balance integration.

Design constraints

  • Money formatting must be exact. Convert stroops to a display string without going through Number for values above 2^53, and reuse or extend src/utils/format.ts.
  • Make no network calls when no vault contract is configured. Show a "not configured" state instead.
  • Simulation needs a source account. Use the connected address when there is one. Otherwise build the read with a valid, fixed, well-formed account and document why it is safe (simulation only, never signed).
  • Debounce refreshes so opening and closing the modal does not flood the RPC. Allow at most one in-flight read per contract.
  • WCAG 2.1 AA: balance updates are announced via a polite live region, and loading skeletons carry aria-busy.

Test plan

Add src/services/vaultReads.test.ts, and extend src/App.deposit.test.tsx and src/components/Dashboard.test.tsx as needed.

# Scenario Expected
1 balance() returns 5000000000 UI shows 500.00 USDC
2 Very large i128 (> 2^53 stroops) formatted exactly, with no float rounding
3 Wallet not connected wallet tile shows "Connect wallet", with no SAC call
4 RPC error inline error and Retry; no 284.62 or 0 shown
5 Deposit confirmed refresh() called; displayed vault value equals the mocked post-deposit balance() and not the local sum
6 Amount > real wallet balance validation message appears, driven by the chain value
7 Max button fills the real wallet balance, truncated to 7 decimals
8 Superseded read an older response resolving after a newer one does not overwrite it
9 Not configured no RPC calls; "Vault not configured" state

Regression proof. Row 5 fails on main, where line 578 computes the sum locally.

Acceptance criteria

  • grep -n "284.62\|1260.5" src/App.tsx returns nothing.
  • Billing, the deposit modal and the Dashboard show the same chain-sourced values.
  • npx tsc -p tsconfig.json --noEmit, npm run build and npx vitest run pass.
  • npm run test:coverage shows at least 90% line coverage for vaultReads.ts and the new hook.
  • docs/Deposit-Flow.md describes the read-back.

Getting started

git checkout -b feat/onchain-vault-balances
npm ci
npx vitest run src/App.deposit.test.tsx
# read-only sanity check against the deployed vault:
stellar contract invoke --id CBJZLUKQBWDMZPKNJAVONZ7GCCWADSETRXWOPN5Z3XWAUNI4F2R7XDYQ --network testnet --send=no -- balance

PR requirements

  • Link this issue.
  • Include before and after screenshots of Billing and the Dashboard at 375px and 1280px.
  • Include a short screen recording of a real testnet deposit followed by the balance refresh.
  • Paste the test and coverage output, and keep the diff focused.
  • Example commit: feat(vault): read vault and wallet balances via Soroban simulation.

Priority rationale

High. Wrong balances on a funding screen erode trust directly and can mislead users about money. The work spans Soroban simulation, i128 precision, async race handling and three surfaces that share state.

Activity

  1. AugistineCreates commented on Oct 18, 2026

    @AugistineCreates
    Contributor

    @AugistineCreates has applied to work on this issue as part of the Stellar Wave Program's 10th wave.

    Hi Maintainer, kindly assign, I can fix this

    ℹ️ Repo Maintainers: To accept this application, review their application or assign @AugistineCreates to this issue.

  2. Adejoke46 commented on Oct 18, 2026

    @Adejoke46

    @Adejoke46 has applied to work on this issue as part of the Stellar Wave Program's 10th wave.

    Hello Maintainer,
    I would like to express my interest in contributing to this issue. I am eager to contribute to the project by helping address the identified problem and delivering a solution that meets the project's requirements.
    I am committed to understanding the issue, following the project's contribution guidelines, testing my work where applicable, and making any necessary improvements based on feedback.
    I value collaboration, clear communication, and quality contributions. I am ready to dedicate the necessary effort to completing this task responsibly and ensuring that my contribution adds value to the project.
    Thank you for considering my application. I look forward to the opportunity to contribute to your project.

    ℹ️ Repo Maintainers: To accept this application, review their application or assign @Adejoke46 to this issue.

  3. IFEANYIBRIGHT commented on Oct 18, 2026

    @IFEANYIBRIGHT
    Contributor

    @IFEANYIBRIGHT has applied to work on this issue as part of the Stellar Wave Program's 10th wave.

    Hi! I’m a full-stack developer with a strong blockchain background. I’d love to handle this issue and can deliver a clean, reliable solution. Kindly assign it to me.

    ℹ️ Repo Maintainers: To accept this application, review their application or assign @IFEANYIBRIGHT to this issue.

  4. raskenite commented on Oct 18, 2026

    @raskenite
    Contributor

    @raskenite has applied to work on this issue as part of the Stellar Wave Program's 10th wave.

    Kindly assign this to me

    ℹ️ Repo Maintainers: To accept this application, review their application or assign @raskenite to this issue.

  5. drips-wave commented on Oct 19, 2026

    @drips-wave

    Congratulations, @IFEANYIBRIGHT! 🎉 Your application was accepted by the repo's maintainers, and the issue is due on October 22, 2026.

    🧑‍💻 @IFEANYIBRIGHT: Please resolve the issue such that the repo's maintainers have enough time to review your contribution before the due date. You'll earn Points for completing the issue on-time, which will make you eligible for a share of the Stellar Wave Program's reward pool.

    Warning

    When opening a PR, please link it to this issue to ensure it gets tracked accurately. Points are awarded when this issue is marked as completed by the maintainer.

    🤠 Repo maintainers: Please keep an eye on the contributor's progress and review their work before the due date. You can manage this issue, including adjusting its complexity and points, here.

    🌊 Happy Wave 🌊

  6. grantfox-oss commented on Oct 21, 2026

    @grantfox-oss

    🎉 This issue has been marked as completed on GrantFox!

    @IFEANYIBRIGHT's PR #1358 was approved and merged by @greatest0fallt1me.

    🏆 @IFEANYIBRIGHT: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (666 total points). Track your full progress on GrantFox.

    👏 Great work, @IFEANYIBRIGHT! Keep contributing to CalloraOrg.

  7. drips-wave commented on Oct 21, 2026

    @drips-wave

    This issue has been completed by @IFEANYIBRIGHT as part of the Stellar Wave Program's 10th Wave 🥳

    😎 @IFEANYIBRIGHT: You earned 100 Points for completing this issue! Once the Wave's rewards are finalized, you'll be eligible for a percentage of the Wave's reward pool based on the percentage of total points you've earned. Learn more here. You can also Leave a review to share your experience working on this issue.

    🧑‍💻 Repo maintainers: How'd the contributor do? Leave a review to share your experience working with them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Stellar WaveStellar Wave Program issuefrontendUI / frontendpriority:highHigh implementation difficultysmart-contractSoroban / Rust contract workvaultVault contract

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions