feat: add ows swap quote command via LI.FI - #192
Conversation
Part of open-wallet-standard#125 Adds ows swap quote — a dry-run cross-chain swap route lookup powered by LI.FI's aggregation API (27 bridges, 31 DEXs, 58 chains). - ows-pay: new swap.rs module with LI.FI quote client, token amount formatting, SwapParams/SwapResult types, swap_dry_run() - ows-cli: new swap subcommand with ows swap quote --wallet --from --to --amount --from-chain --to-chain --slippage --order - No signing in this PR — quote only, transaction_request returned for future signing integration - 3 unit tests for amount formatting (format_amount)
|
@Sertug17 is attempting to deploy a commit to the MoonPay Team on Vercel. A member of the Team first needs to authorize it. |
- swap.rs: expand decimal heuristic to cover WBTC (8), GUSD (2) and BTC-family tokens alongside existing USDC/USDT (6) and default 18 - swap.rs: truncate LI.FI error body to 120 chars to avoid logging full third-party payloads in error messages
|
Addressed both Cursor Bugbot findings: Hardcoded decimals expanded the decimal heuristic to cover WBTC/BTC/SBTC/TBTC (8 decimals), GUSD (2 decimals), and USDC.E/USDT.E (6 decimals) alongside existing USDC/USDT. Default remains 18 for unlisted tokens. Third-party payload logging LI.FI error body is now truncated to 120 chars before being included in the error message. |
- Add ows_chain_to_lifi() mapping (ethereum->1, polygon->137, base->8453, etc.) - Use Solana account address for Solana chains, EVM address for others - Prevents invalid LI.FI requests from unmapped chain names
|
Addressed both Cursor Bugbot findings: LI.FI chain identifiers added ows_chain_to_lifi() that maps OWS Non EVM address mismatch the handler now picks a Solana account |
- ows_chain_to_lifi returns empty string for unknown chains; CLI now returns a clear validation error before making any API call - SwapParams gains optional to_address for cross-VM routes (e.g. ETH->SOL supplies the Solana wallet address as toAddress) - LI.FI quote URL includes toAddress when set
|
Addressed both Cursor Bugbot findings: Unknown chain sent to API ows_chain_to_lifi now returns an empty Missing cross-VM destination address SwapParams gains an optional |
| let body = resp.text().await.unwrap_or_default(); | ||
| let truncated = if body.len() > 120 { | ||
| &body[..120] | ||
| } else { |
There was a problem hiding this comment.
UTF-8 panic truncating errors
Medium Severity
On failed LI.FI responses, the error body is truncated with &body[..120]. If byte 120 falls inside a multibyte UTF-8 character, slicing the str panics and can crash the CLI instead of returning an API error.
Reviewed by Cursor Bugbot for commit bcfd4f8. Configure here.
- ows_chain_to_lifi now accepts eip155:8453, bare numeric IDs (8453), and friendly aliases (ethereum, base, etc.) - Error body truncation uses chars().take(120) to avoid UTF-8 panic on multibyte character boundaries
|
Addressed both Cursor Bugbot findings: Unsupported chain ID formats ows_chain_to_lifi now accepts CAIP-2 UTF-8 panic on truncation error body truncation now uses |
- is_solana now checks lifi_from == '1151111081099592' instead of
contains('solana'), preventing substring false positives
- Transport errors no longer include the request URL (which contains
wallet addresses) — replaced with a generic connection error message
|
Addressed both Cursor Bugbot findings: Substring misclassifies Solana chains — is_solana and is_to_solana Transport errors expose request URL — transport failures now return |
- Move lifi_from/lifi_to validation above from_address resolution - Unsupported chain now returns dedicated error instead of misleading 'no EVM/Solana account found in wallet' message
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a6a42e6. Configure here.
- solana:<ref> now only accepts 'mainnet' and the genesis hash prefix - Any other solana:<ref> returns empty string, triggering the unsupported-chain validation error instead of being passed through as a bare numeric LI.FI chain ID


Part of #125
Adds
ows swap quote— a dry-run cross-chain swap route lookup powered by LI.FI's aggregation API (27 bridges, 31 DEXs, 58 chains).Usage
Changes
ows-pay: new
swap.rsmodule/v1/quoteAPI client (no SDK dependency, pure REST)SwapParams/SwapResulttypesswap_dry_run()— fetches route, formats amounts, returns resultformat_amountows-cli: new
swapsubcommandows swap quotewith flags:--wallet,--from,--to,--amount,--from-chain,--to-chain,--slippage,--orderNot included in this PR
ows bridgealias (same asows swapwith--to-chain)ows swap execute(after signing integration)max_value_usd/allowed_tokenspolicy rulesNote
Medium Risk
Quotes send wallet addresses and swap parameters to a third-party API and rely on decimal heuristics for amounts; no on-chain execution yet, but mis-quotes could mislead users planning trades.
Overview
Adds cross-chain swap quoting to the CLI without signing or broadcasting transactions.
ows-paygains a newswapmodule: a REST client for LI.FI’s/v1/quoteendpoint,SwapParams/SwapResulttypes, human-readableformat_amount, andswap_dry_run()that returns route details (amounts, min received, bridge/DEX tool, gas USD, ETA) while optionally retaining atransactionRequestfor a future execute path.ows-cliwiresows swap quotewith flags for wallet, tokens, amount,--from-chain/--to-chain, slippage, and route order (CHEAPEST / FASTEST). The handler loads the vault wallet, maps OWS/CAIP-2 chain names to LI.FI IDs (EVM + Solana), picks from/to addresses for cross-VM routes, converts human amounts to raw units via token decimal heuristics, and prints a formatted route labeled dry-run.Signing,
swap execute, policy limits, and bridge aliases are explicitly out of scope for this change.Reviewed by Cursor Bugbot for commit 5be2190. Bugbot is set up for automated code reviews on this repo. Configure here.