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

# Fund

> Deposit funds into a wallet, protocol, or chain with the focused Fund component

## Overview

Fund mode implements input-driven deposit flows where users select the amount they want to send. The widget routes funds from any supported chain and token to the destination automatically.

**Trade type**: `EXACT_INPUT` — user specifies input amount, variable output after fees.

## Quick start

Fund supports four payment methods: connected wallet, crypto transfer (QR/address), fiat on-ramp, and exchange (CEX). Set `paymentMethod` to open a specific flow, or omit it to let the user choose.

```tsx theme={null}
import { Fund } from '0xtrails/widget'

// Fiat on-ramp — user buys crypto with a card
<Fund
  apiKey="YOUR_API_KEY"
  paymentMethod="CREDIT_DEBIT_CARD"
  from={{ currency: "USD", amount: 100 }}
  to={{ recipient: "0xYourAddress", token: "USDC", chain: "base" }}
  onFundingSuccess={({ sessionId }) => console.log("funded", sessionId)}
/>
```

```tsx theme={null}
// CEX transfer — user sends from their exchange account
<Fund
  apiKey="YOUR_API_KEY"
  paymentMethod="EXCHANGE"
  from={{ exchange: "coinbase" }}
  to={{ recipient: "0xYourAddress", token: "USDC", chain: "base" }}
/>
```

<Note>
  The exchange (CEX) flow requires your app to be added to the allowlist. Contact us to get access.
</Note>

```tsx theme={null}
// Connected wallet — user pays from their wallet (default)
<Fund
  apiKey="YOUR_API_KEY"
  paymentMethod="CONNECTED_WALLET"
  to={{ recipient: "0xYourAddress", token: "USDC", chain: "base" }}
/>

// Fully open — let the user pick their preferred method
<Fund apiKey="YOUR_API_KEY" />
```

See [Source selection](#source-selection-optional) for all `paymentMethod` values and the `from` options each accepts.

## Props

### Required

| Prop     | Type     | Description    |
| -------- | -------- | -------------- |
| `apiKey` | `string` | Trails API key |

### Destination (optional)

| Prop                        | Type                             | Description                                        |
| --------------------------- | -------------------------------- | -------------------------------------------------- |
| `to.recipient`              | `string`                         | Wallet or contract address that receives the funds |
| `to.token`                  | `string`                         | Destination token — symbol or contract address     |
| `to.chain`                  | `ChainIdentifier`                | Destination chain — name, ID, or viem Chain        |
| `to.defaultToken`           | `string`                         | Default token — user can change                    |
| `to.defaultChain`           | `ChainIdentifier`                | Default chain — user can change                    |
| `to.calldata`               | `string`                         | ABI-encoded calldata to execute after funds arrive |
| `to.supportedChains`        | `ChainIdentifier[]`              | Restrict destination chains the user can pick      |
| `to.supportedTokensByChain` | `SupportedTokensByChainConfig[]` | Per-chain destination token allowlist              |

### Source selection (optional)

Set `paymentMethod` to control how the user funds:

| Value                 | Method                                 |
| --------------------- | -------------------------------------- |
| `"CONNECTED_WALLET"`  | Connected wallet (default)             |
| `"CRYPTO_TRANSFER"`   | QR code / address deposit              |
| `"CREDIT_DEBIT_CARD"` | Fiat on-ramp                           |
| `"EXCHANGE"`          | CEX transfer (Coinbase, Binance, etc.) |

The `from` prop is fully typed based on the selected `paymentMethod`. TypeScript will narrow the allowed fields automatically, so only valid options for that method are accepted.

When `paymentMethod` is set, the `from` object applies to that method:

```tsx theme={null}
// Fiat on-ramp with pre-selected currency and amount
<Fund
  apiKey="YOUR_API_KEY"
  paymentMethod="CREDIT_DEBIT_CARD"
  from={{ currency: "EUR", amount: 100 }}
  to={{ token: "USDC", chain: "base" }}
/>

// Exchange onramp from Coinbase
<Fund
  apiKey="YOUR_API_KEY"
  paymentMethod="EXCHANGE"
  from={{ exchange: "coinbase" }}
  to={{ token: "USDC", chain: "base" }}
/>
```

### Fund method list (optional)

Control which funding methods are shown to the user:

| Prop                      | Type                     | Description                                                                          |
| ------------------------- | ------------------------ | ------------------------------------------------------------------------------------ |
| `fundMethodsList`         | `FundMethodListOption[]` | Ordered list: `"connected-wallet"`, `"crypto-transfer"`, `"cc-onramp"`, `"exchange"` |
| `hideUnlistedFundMethods` | `boolean`                | Hide methods not in `fundMethodsList` (default: `false`)                             |
| `hideSwap`                | `boolean`                | Hide the swap tab in the fund UI (default: `false`)                                  |
| `hideWallets`             | `string[]`               | Wallet addresses to exclude from the source wallet list                              |
| `defaultInputMode`        | `"fiat" \| "token"`      | Default amount input mode                                                            |

### Lifecycle callbacks

| Callback           | Signature                        | When it fires                  |
| ------------------ | -------------------------------- | ------------------------------ |
| `onFundingStart`   | `({ sessionId }) => void`        | User begins the funding flow   |
| `onFundingSuccess` | `({ sessionId }) => void`        | Funding completes successfully |
| `onFundingError`   | `({ sessionId, error }) => void` | Funding encounters an error    |

## Examples

### Buy crypto with a credit card

```tsx theme={null}
import { Fund } from '0xtrails/widget'

<Fund
  apiKey="YOUR_API_KEY"
  paymentMethod="CREDIT_DEBIT_CARD"
  from={{ currency: "EUR", amount: 100 }}
  to={{ token: "USDC", chain: "base" }}
  onFundingSuccess={({ sessionId }) => console.log("funded", sessionId)}
/>
```

### Transfer from a CEX

```tsx theme={null}
<Fund
  apiKey="YOUR_API_KEY"
  paymentMethod="EXCHANGE"
  from={{ token: "USDC", chain: "base", exchange: "coinbase" }}
  to={{ token: "KAT", chain: "katana" }}
/>
```

### QR code / address deposit

```tsx theme={null}
<Fund
  apiKey="YOUR_API_KEY"
  paymentMethod="CRYPTO_TRANSFER"
  to={{
    recipient: "0x...",
    token: "USDC",
    chain: "base",
  }}
/>
```

### Restrict to specific funding methods

Show only fiat and exchange onramps, hide the rest:

```tsx theme={null}
<Fund
  apiKey="YOUR_API_KEY"
  to={{ token: "USDC", chain: "base" }}
  fundMethodsList={["cc-onramp", "exchange"]}
  hideUnlistedFundMethods={true}
/>
```

### Exchange onramp

Users can transfer directly from a CEX account (Coinbase, Binance, Robinhood, and others) without leaving your app. The OAuth connection and transfer are handled automatically — Trails receives the funds and routes them to the destination. No separate account or additional API keys are required.

Pass the `onramp` prop to enable the exchange flow. At minimum, set `environment`:

```tsx theme={null}
<Fund
  apiKey="YOUR_API_KEY"
  onramp={{
    mesh: {
      environment: 'production',
    },
  }}
/>
```

To open the exchange flow directly instead of showing the funding method selector:

```tsx theme={null}
<Fund
  apiKey="YOUR_API_KEY"
  paymentMethod="EXCHANGE"
  onramp={{
    mesh: {
      environment: 'production',
    },
  }}
  to={{ recipient: "0xYourAddress", token: "USDC", chain: "base" }}
  onFundingSuccess={({ sessionId }) => console.log("funded", sessionId)}
/>
```

To restrict which exchanges appear, pass an `exchanges` array:

```tsx theme={null}
<Fund
  apiKey="YOUR_API_KEY"
  onramp={{
    mesh: {
      environment: 'production',
      exchanges: ['coinbase', 'robinhoodDirect'],
    },
  }}
/>
```

For development and testing, use `environment: 'sandbox'`. A yellow banner is shown inside the widget when sandbox is active.

**How the auth flow works:**

1. User selects an exchange from the list.
2. An OAuth popup opens to the exchange's login.
3. After authentication, a transfer confirmation is shown with the amount, token, and destination.
4. User confirms and the withdrawal is initiated from their exchange account.
5. Once detected on-chain, Trails routes the funds to the destination.

The widget shows a pending state while the exchange processes the withdrawal. Session tokens are stored locally for 5 minutes so the user does not have to re-authenticate if they retry.

**Troubleshooting:**

* *Exchange list is empty* — confirm `apiKey` is valid; the exchange list fetch requires a valid API key.
* *Popup blocked* — trigger the flow from a user gesture (button click) rather than programmatically, and encourage users to allow popups for your domain.
* *Session expired* — the exchange session is valid for 5 minutes; a "Refresh Session" button appears if it expires.

***

### Protocol deposit with dynamic calldata

For ERC-4626 vaults and staking contracts where the deposit amount is a function parameter, use `TRAILS_ROUTER_PLACEHOLDER_AMOUNT`. Trails replaces it with the actual bridged/swapped output at execution time.

```tsx theme={null}
import { Fund } from '0xtrails/widget'
import { TRAILS_ROUTER_PLACEHOLDER_AMOUNT } from '0xtrails'
import { encodeFunctionData } from 'viem'

const depositCalldata = encodeFunctionData({
  abi: [{
    name: 'deposit',
    type: 'function',
    stateMutability: 'nonpayable',
    inputs: [
      { name: 'amount', type: 'uint256' },
      { name: 'receiver', type: 'address' },
    ],
    outputs: [{ name: 'shares', type: 'uint256' }],
  }],
  functionName: 'deposit',
  args: [TRAILS_ROUTER_PLACEHOLDER_AMOUNT, '0xReceiverAddress'],
})

<Fund
  apiKey="YOUR_API_KEY"
  to={{
    recipient: "0xYearnVault",
    token: "USDC",
    chain: "katana",
    calldata: depositCalldata,
  }}
  onFundingSuccess={({ sessionId }) => console.log("deposited", sessionId)}
/>
```

<Note>
  Use `TRAILS_ROUTER_PLACEHOLDER_AMOUNT` when the deposit amount is a function parameter and the user selects the amount. Do not use it for functions that read balance internally (e.g. `depositAll()`).
</Note>

## See also

* [Fund use cases](/use-cases/fund) — protocol deposits, trustless deposit addresses
* [Composable actions](/sdk/composable-actions/overview) — programmatic DeFi deposits
* [Configuration reference](/sdk/configuration) — full prop list
