Skip to content

Swap: curated asset list (lobstr API) with search + logos, and custom slippage #318

Description

@Dgetsylver

Problem

The Swap tab hardcodes its asset universe — SWAP_ASSETS (7 classic broker IDs) + BROKER_TO_CONTRACT (4 Soroban contracts) in frontend/src/views/swap.ts. Asset selection is two plain Select dropdowns: no search, no logos. Slippage is limited to three fixed chips (0.1 / 0.5 / 1.0%). Users can't reach most tradable assets, can't search by contract id, and can't set a custom slippage.

Goal

  • Replace the hardcoded list with the LOBSTR curated assets feed: https://lobstr.co/api/v1/sep/assets/curated.json (CORS *, ~51 assets, 14 KB).
  • Let users browse the list or search by contract id to pick sell/buy assets.
  • Show token logos from the feed (icon).
  • Add a 4th slippage option: a custom numeric input (e.g. 2.4, 10, 0.4).

Verified facts

  • Feed is browser-fetchable (Access-Control-Allow-Origin: *); network: "public".
  • Each asset: { contract (64-hex), code, issuer (G…), name, domain, icon (url), decimals }.
  • StrKey.encodeContract(Buffer.from(contract,"hex")) reproduces the real C… id (USDC hex → CCW67TSZ…, EURC → CDTKPWPL…, both match today's hardcoded contracts).
  • XLM is not in the feed → inject a synthetic native entry (brokerId XLM, contract CAS3…).

Plan

1. Data layer — frontend/src/views/swapAssets.ts (new)

  • Fetch + cache the curated feed (in-memory + sessionStorage; refetch when stale).
  • Map each entry → { symbol, name, domain, icon, decimals, issuer, brokerId: "CODE-ISSUER", contractId: StrKey(hex) }.
  • Prepend synthetic XLM.
  • Fallback to the current hardcoded 7 assets if the fetch fails (no dead screen).

2. Searchable asset picker — replaces the two Selects

  • Sell/buy pills (logo + code) open a search modal: text box + scrollable list (logo, code, name, domain).
  • Filter by code / name / domain and contract id — accept both C… StrKey and raw hex.
  • Decision: curated-only. A pasted C… not in the feed shows "not in curated list" (no arbitrary-contract path).
  • Logos via <img loading="lazy"> with a letter-avatar fallback on load error.

3. Custom slippage

  • Keep 0.1 / 0.5 / 1.0 chips; add a 4th Custom chip → numeric input feeding the same slip().
  • Decision: accept 0 < x ≤ 50; show a high-slippage warning above 5%. Reject ≤0 / >50 / non-numeric.

4. Wiring

  • brokerIdestimateSwap; contractIdfetchAssetBalance + aquariusBestRate.
  • Remove SWAP_ASSETS / BROKER_TO_CONTRACT.
  • Execute path unchanged (still gated SWAP_EXECUTE_ENABLED = false).

Files

  • frontend/src/views/swapAssets.ts (new)
  • frontend/src/views/swap.ts
  • frontend/src/views/swap.css

Verification

  • npm run build + npm run lint clean.
  • Live curated fetch + hex→StrKey parity check.
  • Playwright e2e boot suite green (no TDZ/null regression).
  • Manual: browse + search-by-contract-id (C… and hex), pick across pairs, logos render/fallback, custom slippage accept/reject + >5% warning, quote + DEX-rate cross-check still work.

Out of scope

  • Swap execution (broker trade-XDR builder) — remains "coming soon".
  • Arbitrary non-curated contracts.

Metadata

Metadata

Assignees

Labels

Stellar WaveIssues in the Stellar wave program

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions