@decasa/deposit-flow
v0.1.1
Published
Drop-in cross-chain deposit modal. Users top up from any token on any chain and receive the asset you choose, on the network you choose.
Downloads
334
Maintainers
Readme
@decasa/deposit-flow
A drop-in cross-chain deposit modal. Your users top up from any token on any chain and receive the asset you choose, on the network you choose — credited straight to their wallet.
- 🎰 Beautiful, animated, single-column step flow (search → network → amount → deposit → done)
- 🔌 Wallet-agnostic — you pass the receiving
address; the modal never connects a wallet - 🎯 Any destination —
token+networkprops (BNB on BSC, USDC on Base, ETH on Arbitrum…) - 🎨 Themeable — override colors, fonts, and radius; or restyle entirely
- 🌍 i18n-ready — every string is an overridable label (English by default)
- 🧠 Headless option — reuse the state machine, render your own UI
- 🪶 No backend to run — points at a hosted gateway by default
import { DecasaDepositModal } from "@decasa/deposit-flow";
import "@decasa/deposit-flow/styles.css";
<DecasaDepositModal
open={open}
onClose={() => setOpen(false)}
address={userAddress} // the wallet that receives the funds
token="usdc" // what they receive…
network="base" // …and on which chain
/>That's the whole integration. The modal handles asset selection, live quotes, the deposit address + QR + memo, status polling, and the success/failure screens.
Install
npm install @decasa/deposit-flowPeer deps: react >= 18, react-dom >= 18. Everything else (data layer, QR, query cache) is
bundled — there is no react-query setup to do.
Import the stylesheet once, anywhere in your app:
import "@decasa/deposit-flow/styles.css";Usage
1. Controlled modal
Render it conditionally and control visibility yourself:
const [open, setOpen] = useState(false);
<button onClick={() => setOpen(true)}>Deposit</button>
{open && (
<DecasaDepositModal
onClose={() => setOpen(false)}
address={address} // the connected wallet from your app
token="bnb"
network="bsc"
onSuccess={({ amountReceived }) => toast(`+${amountReceived} BNB`)}
/>
)}The modal only receives funds — it never connects a wallet. Pass the address your app already has connected, and gate your "Deposit" button on having one. There's no withdraw path and no connector inside the modal.
2. Provider + hook
Configure once, open from anywhere:
import { DecasaDepositProvider, useDecasaDeposit } from "@decasa/deposit-flow";
<DecasaDepositProvider address={address} token="bnb" network="bsc">
<App />
</DecasaDepositProvider>;
function DepositButton() {
const { open } = useDecasaDeposit();
return <button onClick={open}>Deposit</button>;
}3. Headless
Want a totally different UI? Drive it from the controller and render your own components:
import { useDepositController } from "@decasa/deposit-flow";
const c = useDepositController({
gatewayUrl: DEFAULT_GATEWAY_URL,
destination: { token: "eth", network: "arbitrum" },
address,
featuredSymbols: ["BTC", "ETH", "USDC"],
});
// c.step, c.assets, c.featured, c.estimate, c.quote, c.status, c.submit(), c.pickAsset(), …Note: the headless hook needs a react-query provider in scope. Wrap it in
<QueryClientProvider client={createDepositQueryClient()}>(exported), or just use<DecasaDepositModal>which provides one for you.
Props
| Prop | Type | Description |
| ----------------- | -------------------------------------- | --------------------------------------------------------------------- |
| address | string (required) | Receiving wallet — where funds land. From your app's connected wallet. |
| token | string | Destination token ticker ("bnb", "usdc", "eth"). |
| network | string | Destination network ("bsc", "base", "arbitrum"). |
| onClose | () => void | Close handler. |
| open | boolean | Optional controlled visibility (defaults to shown). |
| theme | Theme | Branding overrides (see below). |
| labels | Partial<Labels> | Copy overrides for i18n / white-labelling. |
| gatewayUrl | string | Gateway base URL. Defaults to the hosted Decasa gateway. |
| featuredSymbols | string[] | Which assets appear in the "Popular" grid. |
| onSuccess | (r: DepositSuccess) => void | Fires once when the deposit settles. |
| onStatusChange | (s: TransactionStatus) => void | Fires on each status poll. |
| explorerTxUrl | (hash: string) => string | Override the success-screen explorer link. |
| statusUrl | (requestId: string) => string | Optional link on the failure screen. |
| destinationLogo | string | Override the destination logo (else derived from the asset list). |
Theming
Every visual token is an overridable CSS variable (--decasa-*). Pass a theme to recolor:
<DecasaDepositModal
theme={{
gold: "#7C5CFF", // primary accent
goldBright: "#9D85FF",
surface: "#15131F",
surface2: "#1E1B2E",
radius: 14,
fontSans: "Inter, sans-serif",
}}
/* … */
/>Omitted keys keep the default gold-on-black look. You can also override the --decasa-*
variables in your own CSS for global rebranding. See Theme for the full key list.
i18n
All copy ships in English and is fully overridable:
<DecasaDepositModal labels={{ title: "Add funds", continue: "Get address", done: "Close" }} />See the Labels type for every key. Placeholders use {name} syntax (e.g.
belowMin: "Min is {min} {symbol}.").
Caching
The supported-asset/network list rarely changes and every uncached request spends the shared API key, so it's cached at three layers automatically:
- localStorage (cross-session) — the asset list is reused for 24h across reloads and every modal open, so a returning user never re-fetches it.
- react-query (in-session) — long stale times dedupe within the app's lifetime.
- the gateway (server) — an in-memory TTL cache plus
Cache-Control(so any CDN/edge in front of the gateway caches it too).
Quotes are always live; status polls every 5s only while a deposit is in flight.
The gateway (hosting)
By default the modal talks to the Decasa-hosted gateway, which holds the exchange-provider API key server-side. You never put a secret in your app, and there's nothing to deploy.
If you want to run your own gateway (e.g. with your own provider key), point the modal at it:
<DecasaDepositModal gatewayUrl="https://gateway.yourapp.com/v1" /* … */ />The gateway logic ships with this package — see gateway-example/ for a
ready-to-deploy Next.js gateway, or wire the framework-agnostic core
(@decasa/deposit-flow/gateway) into any server. The browser only ever talks to the gateway;
the provider key never leaves the server.
License
MIT
