feat: browser swap page (PR #2 of browser-swap roadmap)#86
Open
LandynDev wants to merge 2 commits into
Open
Conversation
Replaces the blurred /swap teaser with a working swap form, wallet connect, state-machine-driven reserve/send/confirm flow, progress UI, browser-side claim button, and a My Swaps tab. Consumes the swap-api FastAPI service introduced in allways#311. - WalletProvider with Polkadot.js (full) and Unisat (full); Xverse/Leather surface as detection-only stubs until v2. - useSwapFlow state machine: idle → awaitingReserveSig → reserving → awaitingSend → sending → awaitingConfirmSig → confirming → watching → done. RateChangedDialog handles 409 responses with re-accept. - usePendingSwap persists intent + signatures + swap id in localStorage keyed by (fromAddress, miner, blockAnchor) so a refresh doesn't lose context. Cross-tab BroadcastChannel arbitration deferred to v2. - ClaimSlashedButton signs the claim_slash extrinsic directly via @polkadot/api when the connected Substrate wallet matches the swap user; falls back to a CLI hint otherwise. - Adds VITE_SWAP_API_URL (default http://localhost:8000) and VITE_SUBTENSOR_WS_URL to .env.example. Refs spec §4–§7 and roadmap PR #2.
… source Cross-repo review surfaced three problems in the browser-swap PR: 1. Xverse and Leather were shipped as `stubAdapter` that throws on every call. The connect dialog showed them as buttons with "(coming soon)". Better to ship Unisat as the BTC adapter and let v2 add others when the signing/sending surfaces actually exist. Removes ~30 lines of apologetic facade. 2. `claimSlash` targeted `api.tx.allways.claimSlash`, but `claim_slash` is an ink! contract selector — not a pallet extrinsic. Replace with `api.tx.contracts.call(VITE_CONTRACT_ADDRESS, 0, gas, null, data)` where `data` is the selector `0xcf3c3dd9` + u64-LE `swap_id`. Same path the validator uses server-side via `contract_client.exec_contract_raw`. Selector kept in sync with `allways/contract_client.py::CONTRACT_SELECTORS`. 3. `STORAGE_KEY = 'allways.pendingSwap'` was a single global slot — a second swap silently nuked the first. Key by (fromAddress, miner, blockAnchor) per spec §4c so parallel swaps coexist; the "pending" pointer is the most-recently-updated entry. 4. TAO-source swaps were gated only inside `sendFunds`, after the reservation had already broadcast on-chain — burning a miner slot. Add a quote-time guard in `SwapForm` so users hit the "use the CLI" message before paying that cost. Build clean; lint clean.
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.
Implements PR #2 of the browser-swap roadmap (
docs/swap-api/pr-roadmap.md). Replaces the blurred/swapplaceholder with a real Uniswap-style swap form wired to the new FastAPIswap-apiservice.Summary
WalletProvidercontext with two production-wired adapters (Polkadot.js / Unisat) and detection-only stubs for Talisman, SubWallet, Xverse, Leather. Connect dialog auto-detects installed extensions.useSwapFlowstate machine drives the full lifecycle:idle → awaitingReserveSig → reserving → awaitingSend → sending → awaitingConfirmSig → confirming → watching → donewith expliciterrorandRateChangedbranches.usePendingSwappersists intent + signature + swap id in localStorage keyed on(fromAddress, miner, blockAnchor)— see spec §4c. Cross-tabBroadcastChannelarbitration is parked for v2.ClaimSlashedButtonsignsallways.claim_slashextrinsic directly via@polkadot/apiwhen the connected Substrate wallet matches the swap'suser_address; falls back to a CLI hint otherwise. Wired intoSwapDetailPageforTIMED_OUTswaps where slash is still pending.MySwapsPagereusesuseAllSwaps({ search })filtered by the connected wallet address. Top nav surfaces "My Swaps" only when a wallet is connected.RateChangedDialoghandles 409 RateChanged responses; user re-accepts the new rate and the flow restarts in place.VITE_SWAP_API_URL(defaulthttp://localhost:8000) andVITE_SUBTENSOR_WS_URLto.env.example.Dependencies
allwaysPR #311 (feat/swap-api) running locally for the UI to function. The roadmap calls this out as ordering: PR ff main #1 must land before this can merge.@polkadot/extension-dapp,@polkadot/api,@polkadot/util-crypto,@polkadot/types. All lazy-loaded — none import at app bootstrap.Spec coverage
/healthz,/chains,/miners,/miners/best,/proofs/reserve,/proofs/confirm,POST /reserve,POST /confirm)v2 deferrals
BroadcastChannelownership arbitration for multi-tab safety (storage events keep tabs roughly in sync today).sendFundsvia@polkadot/apiextrinsic build — error reads "use the CLI" for now; PR Feat/realtime dashboard #2 ships BTC-source happy path.Test plan
npm run build(~6 s; one chunk-size warning from polkadot deps)npm run lintnpm run devboots clean (96 ms),GET /returns 200localhost:9080/swap) with full dev-env + swap-api on :8000RateChangedDialogappears