Skip to content

feat: portfolio reconciliation with real on-chain balances (SOL2-05) - #5

Merged
EKF0 merged 1 commit into
mainfrom
sol2-05/portfolio-reconciliation
May 16, 2026
Merged

feat: portfolio reconciliation with real on-chain balances (SOL2-05)#5
EKF0 merged 1 commit into
mainfrom
sol2-05/portfolio-reconciliation

Conversation

@EKF0

@EKF0 EKF0 commented May 16, 2026

Copy link
Copy Markdown
Owner

Changes

New Infrastructure

  • lib/solana/balances.ts — Fetches native SOL (getBalance) + all SPL tokens (getParsedTokenAccountsByOwner), enriches with catalog metadata, filters dust accounts, sorts by USD value
  • lib/stores/balance-store.ts — Zustand store with refreshCounter for cross-component post-transaction refresh signals
  • hooks/use-wallet-balances.ts — React hook with auto-fetch on wallet connect/disconnect, stale-fetch prevention, and Zustand counter subscription

Dashboard — Mock Data Eliminated

  • holdings-table.tsx — Real token balances with loading skeleton and "No holdings" empty state
  • net-worth.tsx — Real totalValueUsd from on-chain data (day change deferred to SOL6 snapshots)
  • asset-allocation.tsx — Doughnut chart built dynamically from actual wallet holdings

Transaction Refresh

  • deposit-modal.tsx — Calls triggerRefresh() after all receipts confirmed
  • bag-card.tsx — Shows "Your Position" section with actual vs. target allocation and drift indicators

Pricing Note

USD pricing uses a temporary hardcoded price map for SOL/USDC/USDT/JUP/BONK/JitoSOL — real price feed integration is deferred to SOL3-01.

Verification

  • npm run lint ✅ (0 errors, 2 pre-existing warnings)
  • npm run build ✅ (all 11 pages)
  • grep MOCK_HOLDINGS components/ — no results ✅
  • grep 12450.75 components/ — no results ✅

- Created lib/solana/balances.ts: fetches native SOL + SPL tokens via
  getBalance + getParsedTokenAccountsByOwner, enriches with catalog
  metadata, filters dust accounts
- Created lib/stores/balance-store.ts: Zustand refreshCounter for
  cross-component post-transaction refresh signals
- Created hooks/use-wallet-balances.ts: React hook with auto-fetch on
  wallet connect/disconnect and Zustand counter subscription
- Replaced all mock data in dashboard components:
  - holdings-table.tsx: real token list with loading/empty states
  - net-worth.tsx: real totalValueUsd (day change deferred to SOL6)
  - asset-allocation.tsx: dynamic doughnut chart from actual holdings
- deposit-modal.tsx: calls triggerRefresh() after confirmed session
- bag-card.tsx: shows Your Position with actual vs. target allocation
  per asset and drift indicators
- USD pricing uses temporary hardcoded price map — real feed in SOL3
@vercel

vercel Bot commented May 16, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
bagfi Building Building Preview, Comment May 16, 2026 4:35pm

@EKF0
EKF0 merged commit 4159fc6 into main May 16, 2026
1 of 3 checks passed
@EKF0
EKF0 deleted the sol2-05/portfolio-reconciliation branch May 16, 2026 16:36

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e36da4e283

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/solana/balances.ts
Comment on lines +101 to +105
for (const { account } of tokenAccounts.value) {
const parsed = account.data.parsed?.info;
if (!parsed) continue;

const mint: string = parsed.mint;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Aggregate token accounts by mint before computing totals

This loop appends one row per token account, not per mint, so wallets that hold the same mint in multiple accounts (common on Solana) will show duplicated assets and incorrect portfolio math. The net worth/allocation totals are inflated by split accounts, and holdings-table.tsx keys rows by asset.mint, which creates duplicate React keys for this data shape. Collapse balances by mint (summing raw/UI amounts) before building the final array.

Useful? React with 👍 / 👎.

Comment thread lib/solana/balances.ts
Comment on lines +72 to +75
connection.getParsedTokenAccountsByOwner(
publicKey,
{ programId: TOKEN_PROGRAM_ID },
'confirmed'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include Token-2022 accounts when fetching SPL balances

The query only targets TOKEN_PROGRAM_ID, so wallets holding Token-2022 assets will silently miss those balances and show understated net worth/allocations. This is user-visible whenever the connected wallet has any Token-2022 mint. Fetch both classic SPL Token Program and Token-2022 program accounts (or use a merged approach) to match the "all SPL tokens" behavior.

Useful? React with 👍 / 👎.

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