"use client"; import { useEffect, useMemo, useState } from "react"; import { Settings } from "lucide-react"; import { useReducedMotion } from "motion/react"; import { cn } from "@/lib/utils"; import { CHAINS, TOKENS } from "./swap/data"; import { ActionButton, DestinationRow, FlipButton } from "./swap/controls"; import { Field } from "./swap/field"; import { QuoteRow } from "./swap/quote-row"; import { TokenPicker } from "./swap/token-picker"; import type { Chain, Token, TokenSide } from "./swap/types"; import { formatAmount } from "./swap/utils"; export type { Chain, Token } from "./swap/types"; export { SWAP_DRAWER_EASE } from "./swap/constants"; export interface MultiChainSwapProps { chains?: Chain[]; tokens?: Token[]; defaultFromId?: string; defaultToId?: string; className?: string; } export function MultiChainSwap({ chains = CHAINS, tokens = TOKENS, defaultFromId = "eth-eth", defaultToId = "sol-sol", className, }: MultiChainSwapProps) { const reduce = useReducedMotion(); const [fromId, setFromId] = useState(defaultFromId); const [toId, setToId] = useState(defaultToId); const [amount, setAmount] = useState("1"); const [flipRot, setFlipRot] = useState(0); const [quoting, setQuoting] = useState(false); const [picking, setPicking] = useState(null); const [showDest, setShowDest] = useState(false); const [destAddress, setDestAddress] = useState(""); const from = findToken(tokens, fromId); const to = findToken(tokens, toId); const fromChain = findChain(chains, from.chainId); const toChain = findChain(chains, to.chainId); const numericAmount = Number(amount) || 0; const quoteKey = `${numericAmount}:${fromId}:${toId}`; const rate = useMemo(() => { if (!from.usd || !to.usd) return 1; return from.usd / to.usd; }, [from.usd, to.usd]); const toAmount = numericAmount * rate; useEffect(() => { if (!quoteKey) return; if (numericAmount === 0) return; setQuoting(true); const id = setTimeout(() => setQuoting(false), 450); return () => clearTimeout(id); }, [numericAmount, quoteKey]); const flip = () => { setFlipRot((r) => r + 180); setFromId(toId); setToId(fromId); }; const pickToken = (id: string) => { if (!picking) return; if (picking === "from") { if (id === toId) setToId(fromId); setFromId(id); } else { if (id === fromId) setFromId(toId); setToId(id); } setPicking(null); }; return (
Swap
setPicking("from")} /> 0 ? formatAmount(toAmount) : ""} editable={false} quoting={quoting} onOpenPicker={() => setPicking("to")} /> { if (showDest) setDestAddress(""); setShowDest((v) => !v); }} address={destAddress} onAddress={setDestAddress} reduce={!!reduce} />
setPicking(null)} reduce={!!reduce} />
); } function findToken(tokens: Token[], id: string) { const token = tokens.find((t) => t.id === id); if (!token) throw new Error(`Unknown token id: ${id}`); return token; } function findChain(chains: Chain[], id: string) { const chain = chains.find((c) => c.id === id); if (!chain) throw new Error(`Unknown chain id: ${id}`); return chain; }