Skip to content

Repository files navigation

@cherum/widget-react

One signature, many payouts. Your user signs once; Cherum routes the swap and fans it out to up to 12 recipients across Ethereum, Arbitrum, Optimism, Base, Polygon and BNB Chain, in USDC and USDT: the six EVM chains the card quotes and signs on. Paying from TON, Solana, Bitcoin, Tron, XRP and other non-EVM networks happens in the Cherum app the card links to, not in the embedded card.

Self-custody: your user's money goes only to the recipients in the transaction they signed, or back to the wallet that paid. The widget itself runs in an isolated iframe on app.cherum.io, so your page never touches user keys.

You earn on every swap. Pass your wallet as integrator and the Cherum contract pays your fee to it on-chain, in the same transaction. No API key, no approval queue: the wallet address is the whole registration.

When to reach for it

  • Multisend / disperse. Pay up to 12 wallets in one signature instead of N transfers, even when each recipient wants a different chain or a different stablecoin.
  • Batch payouts. Contractor payouts, affiliate or revenue splits: mode="payouts" takes a long list of address + amount rows, typed in or pasted as CSV.
  • Cross-chain swap + bridge in one step. Each leg is quoted across the providers that serve its pair: on the card's chains that means bridges such as Across, Circle CCTP, Stargate, Relay and deBridge, plus DEX aggregators such as KyberSwap and Velora for conversions on one network. One quote, one signature.

Taking payments from your customers (invoices, a hosted payment page, WooCommerce) is a separate product, Cherum Payments. See docs.cherum.io/pay-api.html.

If a leg fails

Each recipient is a separate leg, and a delivered leg is unaffected by one that fails. A leg that can't fill is not lost: its money can go back only to the wallet that paid.

Two cases do not resolve by themselves:

  • deBridge. A stuck deBridge order does not come back on its own. Only the recipient (on the destination network) or deBridge support can cancel it. Once it is cancelled, what was sent through deBridge comes back to the paying wallet in full.
  • Money returned to a Cherum contract. If a bridge sends a leg's refund to a Cherum contract instead of the paying wallet, the card marks that leg "In a Cherum contract" and links to support, who send it on to the wallet that paid.

A refund arrives in the coin the bridge carried, which is not always the one the user paid with. The card labels every leg: delivered, refunded to your wallet (with the amount and the transaction), in a Cherum contract, failed, or in transit.

Install

npm install @cherum/widget-react

Use

import { CherumWidget } from '@cherum/widget-react';

export default function Pay() {
  return (
    <CherumWidget
      integrator="0xYourWalletAddress"
      integratorBps={20}
      theme="dark"
      accent="#8B6FE6"
      source={{ chain: 'arbitrum', token: 'USDC', amount: '1000' }}
      recipients={[
        { chain: 'base', token: 'USDC' },
        { chain: 'optimism', token: 'USDC' },
      ]}
    />
  );
}

One recipient renders a plain swap; two or more switch to fan-out automatically, with no mode flag to manage. Leave source/recipients off and the user picks everything themselves. Recipient addresses are always entered by the user in the card: presets are chain and token only.

Mass payouts

Pass mode="payouts" and the card becomes a payouts form instead: one token on one network, sent to a list of address + amount rows. Recipients can be typed in or pasted as CSV straight from a spreadsheet; big lists are split into batches with pause/resume, and Safe multisigs work as senders. The payer picks the network in the card: the six chains above plus HyperEVM. The Cherum fee on payouts is a flat 0.10% of the batch; your integratorBps markup (up to 300 = 3%) is paid to your wallet in the same transaction, all of it, no split.

<CherumWidget
  mode="payouts"
  integrator="0xYourWalletAddress"
  integratorBps={30}
  source={{ chain: 'base', token: 'USDC' }}
/>

The typed source preset covers the six chains and USDC/USDT. A HyperEVM payout or another token is picked by the payer inside the card. Recipient addresses cannot be pre-filled from config: the person signing always types or pastes the list and confirms the totals themselves.

The component renders the hosted card (app.cherum.io/embed) in an iframe and resizes it to fit via postMessage, so there is no fixed height to guess. The same config maps 1:1 onto the script loader (Cherum.mount('#cherum-widget', {...})) and the raw iframe query string, so moving between the three is mechanical. Try it live in the playground.

Props

prop type meaning
mode 'payouts' Switch the card to mass payouts (address + amount rows, CSV paste). Default is swap / fan-out.
integrator string Your wallet (0x…). Attributes swaps to you and receives your fee.
integratorBps number Your EVM markup in bps (default 20 = 0.2%, cap 500), paid on-chain in the same transaction.
theme 'dark' | 'light' Fix the card theme regardless of the host page. Unset, the card uses the theme saved for your wallet in the dashboard, otherwise the visitor's device setting (dark when there is none).
accent string Brand accent as free HEX (#RRGGBB / #RGB / #RRGGBBAA). Hover and text shades are derived automatically.
radius number Corner radius in px (0–40, default 18); applied to the card and the iframe.
branding boolean Reserved. The swap / fan-out card ignores it and always shows the “Powered by” footer; don't rely on it to remove branding.
lockSource boolean Lock the pre-set source chain/token (checkout-style flows).
source { chain, token, amount? } Pre-select the source.
recipients { chain, token }[] Pre-set fan-out destinations (EVM only, at most 12).
maxWidth number Iframe max width in px (default 460).

chain is one of ethereum, arbitrum, optimism, base, polygon, bsc; token is USDC or USDT where that pair exists on the chain (there is no USDT on Base or Optimism). A pair the card cannot execute is dropped, never substituted, and the card names it on screen.

Supported chains

The swap / fan-out card works between Ethereum, Arbitrum, Optimism, Base, Polygon and BNB Chain, in USDC and USDT (no USDT on Base or Optimism), source and destinations alike. One fan-out of up to 12 legs can mix destination chains and tokens, as long as its recipients are either all on other chains or all on the source chain: the card does not yet combine same-chain and cross-chain recipients in one signature, and says so before you sign.

The rest of Cherum's 25+ networks (live status at cherum.io/status), including Bitcoin, Solana, TON, Tron, XRP, Cardano, Aptos and Zcash, are used in the Cherum app at app.cherum.io, which the card links to. They are not valid source.chain or recipients[].chain values here.

Earnings

Your markup on the card is paid by the Cherum contract to your integrator wallet in the same transaction as the swap or payout, so the block explorer is the receipt and there is nothing to withdraw. That markup does not appear in the dashboard, by design. dashboard.cherum.io (sign in with the same wallet) holds the off-chain revenue-share ledger for routes that run outside the Cherum contract, your rate for those, and ready snippets with your wallet filled in. Full docs: docs.cherum.io.

License

MIT

About

Embeddable cross-chain fan-out swap widget for React — pay many wallets across chains and tokens in one signature

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages