Skip to content

feat(balances): track delegations for Solana - #7903

Merged
limitofzero merged 21 commits into
developfrom
feat/sol-delegation-tracking
Jul 30, 2026
Merged

feat(balances): track delegations for Solana#7903
limitofzero merged 21 commits into
developfrom
feat/sol-delegation-tracking

Conversation

@limitofzero

@limitofzero limitofzero commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Track and surface SPL token delegations for Solana on the account tokens page (/#/account/tokens).

A delegation is the Solana analogue of an EVM allowance: a token account approves the CoW settlement program (via its settlement-state PDA) to pull the sell funds at execution time. This PR fetches that delegation alongside the SPL balance in a single batched read and shows it in the token table's Actions column, mirroring how EVM approvals are displayed — read-only for now, since there is no manual Solana approve flow yet.

image

To Test

set solana flag enabled: localStorage.setItem('IS_SOLANA_ENABLED', '1')

Currently we don't have approve interface for SPL. But you can create a limit order via this demo with enabled solana flag(details) and after this you will see that the source token is approved

Summary by CodeRabbit

Summary

  • New Features
    • Added Solana token delegation allowance/delegation display in token lists, including clear “Approved ✓” and “not delegated” states (supports classic and Token-2022 tokens).
    • Token rows now include an on-chain explorer link for token contracts.
  • Bug Fixes
    • Improved Solana balance + delegation loading with unified batched fetching; EVM allowance fetching is disabled on Solana.
    • Allowance state is no longer persisted across sessions to prevent stale results.
  • Tests
    • Updated and expanded Jest coverage for Solana token-account fetching, delegation matching, and related mocks.

@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cowfi Ready Ready Preview Jul 30, 2026 2:49pm
explorer-dev Ready Ready Preview Jul 30, 2026 2:49pm
storybook Ready Ready Preview Jul 30, 2026 2:49pm
swap-dev Ready Ready Preview Jul 30, 2026 2:49pm
widget-configurator Ready Ready Preview Jul 30, 2026 2:49pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
cosmos Ignored Ignored Jul 30, 2026 2:49pm
sdk-tools Ignored Ignored Preview Jul 30, 2026 2:49pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Solana SPL token account loading now retrieves balances and delegations together, persists them in memory, exposes chain-specific allowances, resets allowance state on account changes, and renders delegation status in token table rows. EVM approval handling remains unchanged.

Changes

Solana SPL account loading

Layer / File(s) Summary
Read Solana token accounts
libs/balances-and-allowances/src/services/*, libs/balances-and-allowances/src/const/solanaSettlement.ts
Batch account reads now return decoded token accounts, balances, and delegated amounts matching the settlement authority, with coverage for missing, malformed, classic, and Token-2022 accounts.

Balance and delegation persistence

Layer / File(s) Summary
Persist balances and delegations
libs/balances-and-allowances/src/hooks/*, libs/balances-and-allowances/src/state/allowancesAtom.ts
The SPL persistence hook stores balances and delegations, uses updated query inputs, and replaces persisted allowance storage with an in-memory atom. Related hook tests are updated and mocked for settlement PDA derivation.

Chain-specific allowance access

Layer / File(s) Summary
Select chain-specific allowances
libs/balances-and-allowances/src/hooks/useTokenAllowances.ts
Solana reads allowances from allowancesAtom without wagmi queries, while EVM chains continue using ERC-20 allowance reads.

Account reset and token presentation

Layer / File(s) Summary
Reset and render delegation state
libs/balances-and-allowances/src/updaters/BalancesResetUpdater.ts, apps/cowswap-frontend/src/legacy/components/Tokens/*, apps/cowswap-frontend/src/locales/en-US.po
Account changes clear allowances, while Solana token rows render em dash, fully approved, or partial delegation states; EVM approval rendering remains conditional on existing content.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TokenRow
  participant useTokenAllowances
  participant allowancesAtom
  participant SPLPersistence
  TokenRow->>useTokenAllowances: request allowance state
  useTokenAllowances->>allowancesAtom: read Solana delegation
  SPLPersistence->>allowancesAtom: write fetched delegation
  allowancesAtom-->>TokenRow: return allowance
  TokenRow->>TokenRow: render delegation status
Loading

Possibly related PRs

Suggested labels: Balances

Suggested reviewers: danziger, fairlighteth, elena-zh

Poem

I’m a bunny with balances, hopping in line,
Delegations and tokens now read just fine.
SPL carrots arrive in one bundled parade,
EVM approvals keep their old lemonade.
“Approved!” I thump, with a whisker-bright cheer!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: tracking Solana delegations.
Description check ✅ Passed The description matches the template's Summary and To Test sections and provides enough implementation context.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sol-delegation-tracking

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@limitofzero
limitofzero marked this pull request as ready for review July 27, 2026 13:04
@limitofzero
limitofzero requested review from a team, azebuado and shoom3301 July 27, 2026 13:04
@limitofzero limitofzero self-assigned this Jul 27, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.test.tsx (1)

98-103: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover delegation persistence, not only balances.

This helper exposes only balancesAtom, while the mock guarantees no delegate match. Add a delegated account case that asserts allowancesAtom receives the mint’s delegated amount; otherwise applySolanaAllowances can regress unnoticed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.test.tsx`
around lines 98 - 103, Extend the test helper and add a delegated-account test
case for usePersistSplViaMulticall. Configure the mocked delegation to match the
relevant mint, then assert that allowancesAtom contains the delegated amount
after applySolanaAllowances runs, while preserving the existing balancesAtom
assertions.
apps/cowswap-frontend/src/legacy/components/Tokens/SplDelegationCell.tsx (1)

1-9: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the explicit component/style file boundary.

Rename this presentational component to SplDelegationCell.pure.tsx, move its label styling behind SplDelegationCell.styled.ts, and import it as a namespace. As per coding guidelines, “Put styles in *.styled.ts” and “Import styles as import * as styledEl from './X.styled'.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/cowswap-frontend/src/legacy/components/Tokens/SplDelegationCell.tsx`
around lines 1 - 9, Rename the presentational component file to
SplDelegationCell.pure.tsx, move its label styling into
SplDelegationCell.styled.ts, and update the component to import that module as
the styledEl namespace. Replace the existing ApproveLabel import and references
with the namespace-based styled element while preserving the component’s
behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libs/balances-and-allowances/src/services/readSolanaTokenAccounts.ts`:
- Around line 23-30: Remove the obsolete {`@link` fetchSolanaTokenBalances}
reference from the documentation above the reader and replace it with generic
wording describing downstream balance and delegation consumers, while preserving
the existing explanation about the single batched account read.

In `@libs/balances-and-allowances/src/state/allowancesAtom.ts`:
- Around line 49-52: Scope cached Solana delegations by wallet account to
prevent same-chain wallet switches from showing stale approvals. In
libs/balances-and-allowances/src/state/allowancesAtom.ts lines 49-52, add an
account dimension or ownership metadata; in
libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.ts lines
106-112, pass the current account and at lines 134-145 persist under its
normalized key or clear stale chain data; in
libs/balances-and-allowances/src/hooks/useTokenAllowances.ts lines 54-56, read
only the current account’s allowance map.

---

Nitpick comments:
In `@apps/cowswap-frontend/src/legacy/components/Tokens/SplDelegationCell.tsx`:
- Around line 1-9: Rename the presentational component file to
SplDelegationCell.pure.tsx, move its label styling into
SplDelegationCell.styled.ts, and update the component to import that module as
the styledEl namespace. Replace the existing ApproveLabel import and references
with the namespace-based styled element while preserving the component’s
behavior.

In `@libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.test.tsx`:
- Around line 98-103: Extend the test helper and add a delegated-account test
case for usePersistSplViaMulticall. Configure the mocked delegation to match the
relevant mint, then assert that allowancesAtom contains the delegated amount
after applySolanaAllowances runs, while preserving the existing balancesAtom
assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b318861-72a2-4412-a599-379c448dbd33

📥 Commits

Reviewing files that changed from the base of the PR and between 473b7e7 and 090112f.

📒 Files selected for processing (14)
  • apps/cowswap-frontend/src/legacy/components/Tokens/SplDelegationCell.tsx
  • apps/cowswap-frontend/src/legacy/components/Tokens/TokensTableRow.tsx
  • apps/cowswap-frontend/src/locales/en-US.po
  • libs/balances-and-allowances/src/const/solanaSettlement.ts
  • libs/balances-and-allowances/src/hooks/usePersistBalancesViaWebCalls.test.tsx
  • libs/balances-and-allowances/src/hooks/usePersistBalancesViaWebCalls.ts
  • libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.test.tsx
  • libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.ts
  • libs/balances-and-allowances/src/hooks/useTokenAllowances.ts
  • libs/balances-and-allowances/src/services/fetchSolanaTokenAccounts.test.ts
  • libs/balances-and-allowances/src/services/fetchSolanaTokenAccounts.ts
  • libs/balances-and-allowances/src/services/fetchSolanaTokenBalances.test.ts
  • libs/balances-and-allowances/src/services/readSolanaTokenAccounts.ts
  • libs/balances-and-allowances/src/state/allowancesAtom.ts
💤 Files with no reviewable changes (1)
  • libs/balances-and-allowances/src/services/fetchSolanaTokenBalances.test.ts

Comment thread libs/balances-and-allowances/src/state/allowancesAtom.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libs/balances-and-allowances/src/updaters/BalancesResetUpdater.ts`:
- Around line 24-35: The account-change guard in the useEffect must use the
SDK’s areAddressesEqual for address comparison instead of prevAccount !==
account. Preserve the existing prevAccount check and explicitly handle
undefined/null values as supported by areAddressesEqual so equivalent EVM
addresses with different casing do not reset balances or allowances.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9f83008a-c112-4701-9820-274817176ef2

📥 Commits

Reviewing files that changed from the base of the PR and between 090112f and 0025e59.

📒 Files selected for processing (2)
  • libs/balances-and-allowances/src/services/readSolanaTokenAccounts.ts
  • libs/balances-and-allowances/src/updaters/BalancesResetUpdater.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/balances-and-allowances/src/services/readSolanaTokenAccounts.ts

Comment thread libs/balances-and-allowances/src/updaters/BalancesResetUpdater.ts

@elena-zh elena-zh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey @limitofzero , thank you, it works as described.
However, I'm not sure in tems on UI:

  1. A green dash is something new that we have never used before . If approval flow wirks defferently, and we don't need to trigger it from this page, then it would be nice simply to change a dash color to
Image

Maybe @fairlighteth has other options to propose.

  1. I'd also not show this dash to a not connected user since it is a useless one.
Image

For a EVM-chain we show 'approve' button that calls 'connect wallet' button, however, not sure if we need this action on Solana network

Image
  1. Lastly: link to a token's details on Blockexplorer is missing for solana on this PR:
Image

However, it is present on other chains

Image

Could you please take a look at these issues?

@limitofzero

Copy link
Copy Markdown
Contributor Author

Hey @limitofzero , thank you, it works as described. However, I'm not sure in tems on UI:

  1. A green dash is something new that we have never used before . If approval flow wirks defferently, and we don't need to trigger it from this page, then it would be nice simply to change a dash color to
Image Maybe @fairlighteth has other options to propose.
  1. I'd also not show this dash to a not connected user since it is a useless one.
Image For a EVM-chain we show 'approve' button that calls 'connect wallet' button, however, not sure if we need this action on Solana network Image 3. Lastly: link to a token's details on Blockexplorer is missing for solana on this PR: Image However, it is present on other chains Image Could you please take a look at these issues?

Hey @elena-zh, thank you, addressed

@limitofzero
limitofzero requested a review from elena-zh July 28, 2026 11:22

@elena-zh elena-zh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks

@shoom3301

Copy link
Copy Markdown
Collaborator

It displays the allowance

image

Comment thread libs/balances-and-allowances/src/const/solanaSettlement.ts Outdated
Comment thread libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.ts
cowswap-release-sync Bot and others added 4 commits July 28, 2026 15:59
# Conflicts:
#	apps/cowswap-frontend/package.json
#	apps/explorer/package.json
#	bundle-size.jsonc
#	libs/events/package.json
#	libs/types/package.json
#	pnpm-lock.yaml
@limitofzero
limitofzero requested a review from shoom3301 July 29, 2026 18:17
@limitofzero
limitofzero enabled auto-merge (squash) July 30, 2026 14:41
@limitofzero
limitofzero merged commit 9fa0bd3 into develop Jul 30, 2026
18 checks passed
@limitofzero
limitofzero deleted the feat/sol-delegation-tracking branch July 30, 2026 14:55
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 30, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants