feat: multi-token (SEP-41) deposit support for pools (Closes #255) - #257
Merged
Merged
Conversation
…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
self-requested a review
August 31, 2026 07:32
Sendi0011
approved these changes
Aug 31, 2026
Sendi0011
left a comment
Contributor
There was a problem hiding this comment.
✅ 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/baseUnitsToHumankeep all conversions in base-units (stroops) with in-rangedecimalsguard (0–18) and reject over-precision (no silent truncation of user funds). Nice. - Defensive route: verifies the tx against Horizon before recording (
successfulcheck, 404→422, unreachable→502 so callers don't mark deposits complete), blocks archived pools, rate-limits, and idempotently skips duplicatetx_hash— preventing double-counted deposits. - Fee math (
computeDepositFee, routefeeBase) uses exact factor-10000 rounding and recordsfee_chargedin the token's own unit. - Minimal, correct migration:
supported_tokens jsonb default '[]'(empty = unrestricted) mirrors the contract'sset_supported_tokenssemantics. i18n in both EN and ES. Unit tests added (deposit-token.test.ts).
Minor (non-blocking — fix forward)
- Settlement
amountis client-trusted — the route validatestoken_amountprecision but does not cross-check the numeric settlementamountagainst the actual on-chain transfer (Horizon ops). Sincetx_hashis verified idempotently it's not a double-spend vector, but consider reconcilingamountfrom Horizon's payment op (or at least clamping/validating it) so the recorded settlement value can't be arbitrary. Same fortreasuryFeeBps/relayerFeeBpsbeing client-supplied. - Idempotency check order — the
existingcheck runs after the Horizon fetch; fine, but doing the (cheap) DB lookup first would save a network call for repeats. Cosmetic. - Consider a small note in
deposit-token.tsthatsupported_tokensnormalization 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.
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 (mirroringdeposit-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→ exactly700000)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 unitcomputeDepositFee— treasury + relayer bps fee computed in the settlement token's own unitfrontend/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:tokenSymbol,tokenDecimals,tokenAmount,treasuryFeeBps,relayerFeeBpstokenAmounthas at most the asset's supported precision (rejects e.g. 8 decimals for a 7-decimal asset)token_amountand a computedfee_chargedalongsideamountso deposit history can be broken out by currencyfrontend/app/api/pools/tokens/route.ts— admin-only route to persist a pool'ssupported_tokensallowlist to Supabase (mirrors contractset_supported_tokensreplace semantics), logging toadmin_actions.Admin config UI —
frontend/components/group/supported-tokens-settings.tsx+useSetSupportedTokens/fetchSupportedTokenshooks that write the allowlist on-chain via the wallet and save it; wired into the group admin controls.Deposit UI token picker —
frontend/components/group/deposit-token-picker.tsxlists supported assets, shows per-token balances (own decimals) and validates selection before deposit.Tracking —
set_supported_tokensregistered as a tracked pending-transaction type (lib/pending-transactions.ts,lib/tx-retry.ts).Schema —
pools.supported_tokensJSONB column viasupabase/migrations/20260827000000_multi_token_deposits.sql, reflected in the typed client (lib/supabase.ts).Verification
tsc --noEmitreports no new errors from changed files (pre-existing unrelated errors untouched)Closes #255