Skip to content

feat: multi-token (SEP-41) deposit support for pools (Closes #255) - #257

Merged
Sendi0011 merged 2 commits into
JointSave-org:mainfrom
devJaja:feat/multi-token-deposit
Aug 31, 2026
Merged

feat: multi-token (SEP-41) deposit support for pools (Closes #255)#257
Sendi0011 merged 2 commits into
JointSave-org:mainfrom
devJaja:feat/multi-token-deposit

Conversation

@devJaja

@devJaja devJaja commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements end-to-end multi-token (SEP-41) deposit support for pools, per issue #255. The rotational contracts already expose set_supported_tokens / get_supported_tokens; this PR wires the frontend admin configuration, token-aware deposit route and amount maths around them.

What changed

frontend/lib/deposit-token.ts — new dependency-free pure-logic module (mirroring deposit-calendar.ts / batch-deposit.ts) shared by the deposit UI and API:

  • humanToBaseUnits / baseUnitsToHuman / trimHumanAmount — exact human ↔ base-units conversion per asset decimals, immune to float error ("0.07" @ 7 → exactly 700000)
  • validateTokenSelection — checks a chosen token against the pool's supported set (empty list = unrestricted)
  • checkSufficientBalance — validates a human amount against an on-chain base-units balance in the correct unit
  • computeDepositFee — treasury + relayer bps fee computed in the settlement token's own unit

frontend/lib/deposit-token.test.ts — 24 unit tests covering decimals conversion, token selection, balance checks and fee maths.

frontend/app/api/pools/deposit/route.ts — token-aware deposit route:

  • Accepts optional tokenSymbol, tokenDecimals, tokenAmount, treasuryFeeBps, relayerFeeBps
  • Validates that tokenAmount has at most the asset's supported precision (rejects e.g. 8 decimals for a 7-decimal asset)
  • Records token_amount and a computed fee_charged alongside amount so deposit history can be broken out by currency

frontend/app/api/pools/tokens/route.ts — admin-only route to persist a pool's supported_tokens allowlist to Supabase (mirrors contract set_supported_tokens replace semantics), logging to admin_actions.

Admin config UIfrontend/components/group/supported-tokens-settings.tsx + useSetSupportedTokens / fetchSupportedTokens hooks that write the allowlist on-chain via the wallet and save it; wired into the group admin controls.

Deposit UI token pickerfrontend/components/group/deposit-token-picker.tsx lists supported assets, shows per-token balances (own decimals) and validates selection before deposit.

Trackingset_supported_tokens registered as a tracked pending-transaction type (lib/pending-transactions.ts, lib/tx-retry.ts).

Schemapools.supported_tokens JSONB column via supabase/migrations/20260827000000_multi_token_deposits.sql, reflected in the typed client (lib/supabase.ts).

Verification

  • 268/268 unit tests pass (24 new)
  • 121/121 component tests pass across 19 files
  • ESLint clean, Prettier formatted, tsc --noEmit reports no new errors from changed files (pre-existing unrelated errors untouched)

Closes #255

devJaja and others added 2 commits August 27, 2026 19:05
…e-org#255)

- Add pure-logic deposit-token module (human<->base-units per asset
  decimals, token-selection validation, balance checks, fee math) with full
  unit test coverage.
- Extend POST /api/pools/deposit to accept token selection, validate the
  token amount against the asset's precision, and record token_amount +
  computed fee alongside the numeric amount.
- Add POST /api/pools/tokens admin route to persist a pool's supported-token
  allowlist (admin-only), and a SupportedTokensSettings admin UI that writes
  the allowlist on-chain via set_supported_tokens and saves it to Supabase.
- Add useSetSupportedTokens/fetchSupportedTokens contract hooks and register
  set_supported_tokens as a tracked pending-transaction type.
- Introduce a DepositTokenPicker on the deposit panel that lists supported
  assets, shows per-token balances, and validates selection.
- Add pools.supported_tokens column via migration and update the typed
  Supabase client.
@Sendi0011
Sendi0011 self-requested a review August 31, 2026 07:32

@Sendi0011 Sendi0011 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.

✅ Approve — solid, well-engineered multi-token deposit (#255)

Clean, senior-quality implementation. Integer-exact SEP-41 handling and a defensive deposit-verification route. A few minor points to consider (non-blocking).

Strengths

  • Exact arithmetic: humanToBaseUnits / baseUnitsToHuman keep all conversions in base-units (stroops) with in-range decimals guard (0–18) and reject over-precision (no silent truncation of user funds). Nice.
  • Defensive route: verifies the tx against Horizon before recording (successful check, 404→422, unreachable→502 so callers don't mark deposits complete), blocks archived pools, rate-limits, and idempotently skips duplicate tx_hash — preventing double-counted deposits.
  • Fee math (computeDepositFee, route feeBase) uses exact factor-10000 rounding and records fee_charged in the token's own unit.
  • Minimal, correct migration: supported_tokens jsonb default '[]' (empty = unrestricted) mirrors the contract's set_supported_tokens semantics. i18n in both EN and ES. Unit tests added (deposit-token.test.ts).

Minor (non-blocking — fix forward)

  1. Settlement amount is client-trusted — the route validates token_amount precision but does not cross-check the numeric settlement amount against the actual on-chain transfer (Horizon ops). Since tx_hash is verified idempotently it's not a double-spend vector, but consider reconciling amount from Horizon's payment op (or at least clamping/validating it) so the recorded settlement value can't be arbitrary. Same for treasuryFeeBps/relayerFeeBps being client-supplied.
  2. Idempotency check order — the existing check runs after the Horizon fetch; fine, but doing the (cheap) DB lookup first would save a network call for repeats. Cosmetic.
  3. Consider a small note in deposit-token.ts that supported_tokens normalization is case-insensitive on the tokens themselves but the contract likely treats addresses as exact — keep the comparison consistent with how the contract stores them.

Coordination

This closes #255 and overlaps with PR #256 (also closes #255, same files: deposit/route.ts, group-actions.tsx, deposit-token.ts). This PR is the more complete of the two (DB migration + token settings UI + retry support) and is currently mergeable-clean, whereas #256 is dirty. Recommend merging this one and closing/superseding #256 to avoid a conflict and a double-implementation of the same feature.

Nice work. Approved for merge once green.

@Sendi0011
Sendi0011 merged commit 4d4083b into JointSave-org:main Aug 31, 2026
5 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.

[Feature] End-to-end multi-token (SEP-41) deposit support for pools

2 participants