Stablecoin swap#6
Merged
Merged
Conversation
Add a Lightning → USDC/USDT-on-Ethereum swap flow so users can off-ramp to stablecoins without leaving avark.
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.
BTC → stablecoin swaps + WalletConnect + LN recovery
Summary
Adds BTC → stablecoin (USDC/USDT on Ethereum) swaps via LendaSwap, WalletConnect for destination addresses, and a recovery screen for stuck Lightning submarine swaps. Architecturally pivots LendaSwap integration from Rust-side
lendaswap-coreto the TypeScript@lendasat/lendaswap-sdk-pure; Rust keeps a DB-only persistence layer (lendaswap.db) so swap history survives restarts and the reconciler catches up on app boot.What's new
User-facing
/swap(quote, token picker, destination via paste or WalletConnect)/swap/checkout/$id— pay from avark or via external Lightning wallet (QR + invoice copy), in-app claim button once swap reachesprocessing, status pulse + polling/swap/history(paginated, newest-first)/recover/ln) — list pending submarine swaps with refund actions (cooperative refund via Boltz, or unilateral when timelock expires)Routing…instead of hanging when a Lightning payment's settlement takes longer than 30s — VHTLC is funded, settlement is in flight, recovery screen handles the restBackend (Rust)
lendaswap.db(SQLite) withlendaswap_swapstable; opened attauri::Builder::setup, cleared on wallet deleteinsert_lendaswap_swap,update_lendaswap_swap_status,dismiss_lendaswap_swap,get_lendaswap_swap,list_lendaswap_swapsget_lendaswap_xprv— derives a purpose-isolated xprv atm/887'/0'and hands it to the WebView. The BIP39 mnemonic stays Rust-only; a WebView compromise can drain LendaSwap-purpose keys but not the main walletlist_pending_submarine_swaps+refund_submarine_swapfor the recovery flowtauri-plugin-httpregistered so the frontend fetch-proxy can reach API hosts whose CORS doesn't whitelist mobile WebView originsFrontend (TS)
src/lib/lendaswap/client.ts— SDK wrapper, IDB legacy-purge (scrubs pre-pivotlendaswap-v2/v3DBs that stored the mnemonic), Boltz-Arkade preflight, fee scaling, status mappingsrc/lib/lendaswap/reconcile.ts— once-per-session catch-up on non-terminal swapssrc/lib/tauriFetch.ts— installs aglobalThis.fetchproxy at app boot, routes only the explicitly-allowed hosts through Tauri's HTTP plugin@walletconnect/sign-client(session restore, mobile deep-link → QR fallback)Security model
m/887'/0', not the wallet's root mnemonic. The SDK'swithXprv(...)is documented as ephemeral (never written to IndexedDB), so the xprv only lives in WebView session memory887'is unused by the standard BIP registry; the trailing0'is a generation counter (bump to1'to invalidate the swap subtree without rotating the mnemonic)http:defaultis scoped to an explicit URL allowlist — no wildcard*Configuration
VITE_WALLETCONNECT_PROJECT_ID(required for swaps; missing → "WalletConnect not configured" screen). Add as a GitHub Actions Variable; release.yml is wiredsrc-tauri/capabilities/default.json: HTTP allowlist for LendaSwap, Boltz, ASPs, WalletConnect relay/verify; opener allow-rule forwc:*lendaswap.dblives alongsidewallet.db/swaps.db/boarding.dbin the app data dir and is cleared bydelete_walletMigration / data handling
rebuild_fee_columns_if_legacy) rebuilds the table to INTEGER fee columns if a dev install has the original TEXT shape. Safe pre-release because the only rows present are dev test datalendaswap-v2/lendaswap-v3databases, flagged via localStorage so it runs at most once per installKnown limitations / follow-ups
swap-checkout-route.tsxis 1,089 lines — sub-components can be extracted; tracked as cleanupreconcile.ts, two route files) — should converge on one source of truthTest plan
processing, claim, confirmcompleted+ Etherscan tx hash rendersawaiting_paymentswap to age past 10 min, confirm dismiss footer appears and works/recover/ln; confirm the stuck swap is listed and refund succeedslendaswap.dbis removed and a subsequent restore doesn't hitMnemonicMismatchcargo fmt --check,cargo clippy -- -D warnings,cargo test,pnpm tsc,pnpm lintpnpm tauri android build -- --features vendored-openssl,pnpm tauri ios build