> ## Documentation Index
> Fetch the complete documentation index at: https://docs.etherfuse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Base

> EVM asset identifiers, the ERC-20 approval step, gasless offramps, and minimum offramp size on Base.

export const ChainAssets = ({chain}) => {
  const {useState, useEffect} = React;
  const [rows, setRows] = useState(null);
  const [error, setError] = useState(null);
  const EXPLORER = {
    solana: id => 'https://solscan.io/token/' + id,
    stellar: id => 'https://stellar.expert/explorer/public/asset/' + id,
    base: id => 'https://basescan.org/token/' + id,
    polygon: id => 'https://polygonscan.com/token/' + id,
    monad: id => 'https://monadvision.com/token/' + id
  };
  const CHAIN_LABEL = {
    stellar: 'Stellar',
    solana: 'Solana',
    monad: 'Monad',
    base: 'Base',
    polygon: 'Polygon'
  };
  const tokenLogo = s => 'https://stablebonds.s3.us-west-2.amazonaws.com/stablebond/spl-' + String(s).toLowerCase() + '.png';
  const hideOnError = e => {
    e.currentTarget.style.display = 'none';
  };
  useEffect(() => {
    let cancelled = false;
    fetch('https://api.etherfuse.com/lookup/stablebonds').then(r => {
      if (!r.ok) throw new Error('HTTP ' + r.status);
      return r.json();
    }).then(data => {
      if (cancelled) return;
      setRows(data.stablebonds || []);
    }).catch(e => {
      if (!cancelled) setError(e.message || 'failed to load');
    });
    return () => {
      cancelled = true;
    };
  }, []);
  const border = '1px solid rgba(128,128,128,0.25)';
  const cell = {
    padding: '6px 12px',
    borderBottom: border,
    textAlign: 'left',
    verticalAlign: 'middle'
  };
  const head = {
    ...cell,
    fontWeight: 600
  };
  const mono = {
    fontFamily: 'monospace',
    fontSize: '0.85em',
    wordBreak: 'break-all'
  };
  const inline = {
    display: 'inline-flex',
    alignItems: 'center',
    gap: '6px'
  };
  if (error) return <p>
        Couldn't load the live list. See <code>GET /lookup/stablebonds</code>.
      </p>;
  if (!rows) return <p>Loading live addresses…</p>;
  const items = (rows || []).filter(b => b.symbol !== 'MEX').map(b => {
    const entry = (b.blockchains || []).find(c => c.blockchain === chain);
    return entry ? {
      symbol: b.symbol,
      currency: b.bondCurrency,
      id: entry.tokenIdentifier
    } : null;
  }).filter(Boolean).sort((a, z) => String(a.symbol).localeCompare(String(z.symbol)));
  if (!items.length) return <p>No stablebonds are currently live on {CHAIN_LABEL[chain] || chain}.</p>;
  return <div>
      <table style={{
    width: '100%',
    borderCollapse: 'collapse',
    fontSize: '0.95em'
  }}>
        <thead>
          <tr>
            <th style={{
    ...head,
    width: '160px'
  }}>Asset</th>
            <th style={head}>Address</th>
          </tr>
        </thead>
        <tbody>
          {items.map(it => {
    const url = EXPLORER[chain] ? EXPLORER[chain](it.id) : null;
    return <tr key={it.symbol}>
                <td style={cell}>
                  <span style={inline}>
                    <img src={tokenLogo(it.symbol)} alt="" width={20} height={20} onError={hideOnError} />
                    <strong>{it.symbol}</strong>
                    <span style={{
      opacity: 0.6
    }}>· {it.currency}</span>
                  </span>
                </td>
                <td style={{
      ...cell,
      ...mono
    }}>
                  {url ? <a href={url} target="_blank" rel="noreferrer">
                      {it.id}
                    </a> : it.id}
                </td>
              </tr>;
  })}
        </tbody>
      </table>
      <p style={{
    fontSize: '0.8em',
    opacity: 0.65,
    marginTop: '8px'
  }}>
        Live from <code>GET https://api.etherfuse.com/lookup/stablebonds</code>. Production addresses — when quoting,
        use the <code>identifier</code> from <code>GET /ramp/assets</code> (sandbox differs).
      </p>
    </div>;
};

<img src="https://mintcdn.com/etherfuse/XRSchVFGUgreQatD/img/chains/base.svg?fit=max&auto=format&n=XRSchVFGUgreQatD&q=85&s=2e66b7c72272a611f386d0912e488507" alt="Base" width="64" noZoom style={{ float: "right", margin: "0 0 1rem 1.5rem" }} data-path="img/chains/base.svg" />

Base is supported for onramps and offramps. As an EVM chain, assets are plain ERC-20 contracts and offramps need a one-time **token approval** before the customer can sell — with **gasless offramps**, the user doesn't even need ETH. The end-to-end flows live in the [Onramps](/guides/testing-onramps) and [Offramps](/guides/testing-offramps) guides.

## Supported operations

| Operation              | Supported                                                                                                                      |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| Onramp (fiat → token)  | ✓                                                                                                                              |
| Offramp (token → fiat) | ✓                                                                                                                              |
| Swap (token → token)   | ✗ — not yet on Base ([Stellar](/guides/chains/stellar) / [Solana](/guides/chains/solana) / [Monad](/guides/chains/monad) only) |

## Asset identifiers

Base assets are identified by the **raw token contract address only** — e.g. `0xcC77c598d42f2f78Beb42C91d12B9d4041a5cE29`.

<Warning>
  **Do not prefix with a symbol.** Using `SYMBOL:0x...` (the Stellar-style format) on an EVM chain returns `UnsupportedBlockchain`. Pass just the `0x…` address from [`GET /ramp/assets?blockchain=base`](/api-reference/assets/list-assets).
</Warning>

## Stablebond addresses

Live token-contract addresses for every stablebond on Base, each linked to Basescan:

<ChainAssets chain="base" />

## Offramps: approve the token first

Selling an ERC-20 requires a standard `approve()` so Etherfuse's contracts can move the token. Generate that approval with [`POST /ramp/evm/approve`](/api-reference/sponsored/approve-evm-token) **before** creating the offramp order — otherwise the offramp transaction fails on-chain.

```bash theme={null}
curl -X POST https://api.sand.etherfuse.com/ramp/evm/approve \
  -H "Authorization: <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "blockchain": "base",
    "wallet": "0xf82567432381D1326484E5A9140ABCa4294f82D0",
    "assetId": "0xcC77c598d42f2f78Beb42C91d12B9d4041a5cE29"
  }'
```

* **Omit `amount`** (recommended) to approve the maximum — a one-time approval per token per chain covers all future offramps. Or pass `amount` in base units to approve a specific amount.
* If a sufficient allowance already exists, the response is `{"transaction": null}` — nothing to sign, go straight to the order.
* Otherwise, have the user **sign and submit** the returned transaction, then create the offramp via [`POST /ramp/order`](/api-reference/orders/create-order).

## Gasless offramps

When gasless offramps are enabled for your organization, **Etherfuse covers the native gas** (ETH on Base) for the offramp and bundles that cost into the offramp fee — so your users don't need to hold ETH.

<Warning>
  **Minimum offramp size.** Because the combined fee can never exceed **50% of the order**, very small offramps are rejected with `OrderTooSmall` ("Combined fee … exceeds maximum (5000 bps / 50%)"). The bundled gas cost is roughly \$0.50, so offramp at least \~50 CETES (or equivalent) at a time. See [Errors](/errors).
</Warning>

<Info>
  Gasless offramps and the `POST /ramp/evm/approve` flow are **feature-gated per organization** — contact Etherfuse to enable them.
</Info>

## Related

<CardGroup cols={2}>
  <Card title="Onramps" icon="arrow-up-right-dots" href="/guides/testing-onramps" />

  <Card title="Offramps" icon="arrow-down" href="/guides/testing-offramps" />
</CardGroup>
