> For the complete documentation index, see [llms.txt](https://docs.lighter.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.lighter.xyz/developers/integration-guides/deposits-transfers-and-withdrawals.md).

# Deposits, Transfers and Withdrawals

| Method                                                                               | Chains                                                                                              | Assets credited            | Best for                                        |
| ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------------- |
| [Universal Deposit Address (UDA)](#deposit-via-fun.xyz) – recommended                | Ethereum, Arbitrum, Base, Optimism, Polygon, BNB, HyperEVM, Monad, Robinhood, Solana, Tron, Bitcoin | USDC or ETH, perps or spot | Wallets & apps: one address per user, any chain |
| [Direct Ethereum deposit](#deposit-via-ethereum-mainnet)                             | Ethereum mainnet                                                                                    | Any listed asset           | Users already on Ethereum; contracts            |
| [CCTP intent address](#legacy-deposit-usdc-via-other-evm-compatible-chains) (legacy) | Arbitrum, Base, Avalanche, Arc                                                                      | USDC                       | Existing integrations                           |

The first credited deposit **creates the account**. See [Create accounts programmatically](/developers/integration-guides/create-accounts-programmatically.md).

## Deposit via Ethereum Mainnet

To deposit via Ethereum mainnet, you can use the `deposit` method (0x8a857083) directly. You'll need to specify the following parameters:

* `deposit`: the amount of Ether you're depositing. That is optional and only needed when interacting with the contract directly, Lighter's Ethereum gateway page does not require this. You can leave this at zero if you're depositing other kinds of assets.
* `_to`: the L1 address you want to credit the deposit to
* `_assetIndex`: the asset you want to deposit. You can grab the correct asset id from the [assetDetails](https://docs.lighter.xyz/api/orders) endpoint
* `_routeType`: whether you want to deposit the asset to your perps (0), or spot account (1). Only USDC can be deposited to your perps account
* `_amount`: the amount you're depositing. *it should be in line with the ERC20's decimals. E.g. 6 decimals for USDC, 18 decimals for Ether etc. 1 USDC, or equivalent, minimum.*

If you're depositing assets different from ETH (e.g. USDC), make sure to approve spending for Lighter's smart contract (0x3B4D794a66304F130a4Db8F2551B0070dfCf5ca7) for that ERC20. There is a minimum of 1 USDC, and equivalent for other ERC20s, per deposit.

Example with [viem](https://viem.sh), where `wallet` is a WalletClient connected to the user's wallet on Ethereum mainnet:

```typescript
import { parseUnits, erc20Abi } from "viem";

const LIGHTER = "0x3B4D794a66304F130a4Db8F2551B0070dfCf5ca7";
const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
const amount = parseUnits("100", 6);

await wallet.writeContract({ address: USDC, abi: erc20Abi, functionName: "approve", args: [LIGHTER, amount] });
await wallet.writeContract({
  address: LIGHTER,
  abi: lighterAbi, // fetch from Etherscan (proxy implementation)
  functionName: "deposit",
  args: [userAddress, usdcAssetIndex, 0 /* perps */, amount],
});
```

## Deposit via Fun.xyz

Generate a Universal Deposit Address (UDA) address for each client, for any supported chain.

* **Base URL**: `https://bridge.lighter.xyz`
* **Authentication**: every request needs to include `x-api-key` in its header. Builders can contact us through [Discord tickets](https://discord.gg/lighterxyz) via #support to request one.

For new users, depositing will automatically create an account on Lighter and assign the wallet an `account_index`.

### Supported Assets

| Chain           | Supported Assets                                      | Chain ID |
| --------------- | ----------------------------------------------------- | -------- |
| Ethereum        | `USDC, USDT, cbBTC, DAI, ETH, MATIC, POL, USDe, wETH` | `1`      |
| Robinhood       | `USDG`                                                | `4663`   |
| Arbitrum        | `USDC, USDT, DAI, ETH, USDe, wETH`                    | `42161`  |
| Solana          | `USDC, USDT, SOL, TRUMP, USDe`                        | `N/A`    |
| BNB Smart Chain | `USDC, USDT, BNB, BUSD, BTCB, DAI, ETH, USDe, wBNB`   | `56`     |
| Base            | `USDC, USDT, cbBTC, DAI, ETH, USDe, wETH`             | `8453`   |
| Polygon         | `USDC, USDT, DAI, MATIC, POL, USDC.e, wETH`           | `137`    |
| HyperEVM        | `USDC, USDT, HYPE, uBTC, USDe`                        | `999`    |
| Optimism        | `USDC, USDT, DAI, ETH, wETH`                          | `10`     |
| Monad           | `USDC, MON`                                           | `143`    |
| Tron            | `USDT`                                                | `N/A`    |
| Bitcoin         | `BTC`                                                 | `N/A`    |

### Deposit Minimums

| Source                | New account | Existing account |
| --------------------- | ----------- | ---------------- |
| Ethereum mainnet      | $5          | $5               |
| EVM-compatible chains | $5          | $3               |
| Solana                | $5          | $3               |
| Tron                  | $5          | $5               |
| Bitcoin               | $10         | $10              |

Note that depositing slightly larger amounts than the minimums advertised above is suggested, as bridge and swap operations may incur slippage and result in a lower amount.

### Create a Universal Deposit Address (UDA)

* `POST` request to `https://bridge.lighter.xyz/v1/uda`
* `Content-Type`: `application/json`

| Field           | Type   | Notes                                                                                                                  |
| --------------- | ------ | ---------------------------------------------------------------------------------------------------------------------- |
| `walletAddress` | string | The client's EVM wallet, where funds will be credited                                                                  |
| `market`        | string | `"perps"` or `"spot"`                                                                                                  |
| `asset`         | string | `"USDC"` or `"ETH"`. This is what the deposit asset gets converted to, when credited on Lighter                        |
| `accountIndex`  | number | Optional. It can be used to target a sub-account; if you omit it, the deposit is credited to the master account index. |

**JSON Body example**

```json
{
  "walletAddress": "0x1111111111111111111111111111111111111111",
  "market": "perps",
  "asset": "USDC"
}
```

**Example Response (200)**

```json
{
  "depositAddr": "0x2222222222222222222222222222222222222222",
  "solanaAddr": "So1anaDepositAddressExample11111111111111111",
  "tronAddr": "TTronDepositAddressExample1234567890",
  "btcAddrSegwit": "bc1qexampledepositaddress0000000000000000",
  "blocked": false,
  "resolved": {
    "toChainId": "3586256", // lighter's chain id
    "toTokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    "actionType": "LIGHTER_PERPS",
    "recipientAddr": "1234", // client's account index, or l1 if the account is new
    "userId": "0x1111111111111111111111111111111111111111"
  }
}
```

Deposit addresses are used to route and credit the amount to the client's address (returned as `userId` and `recipientAddr`). Show the address for the chain the user picks, and check `blocked` before displaying it. Call the bridge API **server-side only**: never expose the `x-api-key` in a client.

### Generate a Quote (optional)

* `POST` request `https://bridge.lighter.xyz/v1/uda/quote`
* `Content-Type`: `application/json`

| Field                | Type   | Notes                                                       |
| -------------------- | ------ | ----------------------------------------------------------- |
| `fromAmountBaseUnit` | string | Amount the user will send, in the source token's base units |
| `fromChainId`        | string | Source Chain ID                                             |
| `fromTokenAddress`   | string | Source Token Address                                        |
| `recipientAddress`   | string | The user's wallet (equal to `walletAddress`)                |
| `toChainId`          | string | Destination Chain ID (`resolved.toChainId`)                 |
| `toTokenAddress`     | string | Destination Token (`resolved.toTokenAddress`)               |

**JSON Body Example**

```json
{
  "fromAmountBaseUnit": "5000000",
  "fromChainId": "42161",
  "fromTokenAddress": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
  "recipientAddress": "0x1111111111111111111111111111111111111111",
  "toChainId": "1",
  "toTokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
}
```

**Example Response (200)**

```json
{
  "estCheckoutTimeMs": 25000,
  "estFeeBreakdown": {
    "appFeeLabel": "Fun fee",
    "appFeePercent": 0,
    "appFeeUsd": 0,
    "fillCostPercent": 0,
    "fillCostUsd": 0,
    "gasUsd": 0.000465,
    "maxSlippage": 0,
    "minReceived": 4.99,
    "swapImpact": 0,
    "swapImpactUsd": 0,
    "totalImpact": 0,
    "totalImpactUsd": 0
  },
  "estInputUsd": 5.0,
  "estOutputUsd": 4.99,
  "estToTokenBaseUnit": "4990000",
  "quoteId": "0xeb9f1ac3..."
}
```

Use this to show the user an estimated amount received, fees, and arrival time before they send funds. Quotes are estimates only. The `UDA` generated above works without one.

### Track Deposit Status

`GET` request to `https://bridge.lighter.xyz/v1/uda/status/{walletAddress}`

`walletAddress` is the client's wallet, the same one used to generate a UDA above, and returned as `userId`.

**Example Response (200)**

```json
{
  "transactions": [
    {
      "fromChainId": "42161",
      "fromTokenAddress": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
      "fromAmountBaseUnit": "4999999",
      "toChainId": "3586256",
      "toTokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "txHash": "0xabc123...",
      "createdTimeMs": 1787068237169,
      "status": "COMPLETED",
      "depositAddr": "0x2222222222222222222222222222222222222222"
    }
  ]
}
```

Deposits appear with status: `"PROCESSING"` shortly after the user’s transaction confirms on the source chain, and moves to `"COMPLETED"` once the funds are credited on Lighter, typically within a few minutes.

## Errors

**Example error**

```json
{ "errorCode": "InvalidParameterError", "errorMsg": "market must be \"spot\" or \"perps\"" }
```

| HTTP  | `errorCode`                   | Meaning                                                 |
| ----- | ----------------------------- | ------------------------------------------------------- |
| `400` | `InvalidParameterError`       | Malformed body, unsupported market/asset, bad address   |
| `403` | `InsufficientPermissionError` | Missing/invalid API key, or wallet not generated by you |
| `502` | `DependencyFailureError`      | Upstream temporarily unavailable, retry with backoff    |

## Example (TypeScript)

```typescript
const BASE = "https://bridge.lighter.xyz";
const KEY = process.env.LIGHTER_BUILDER_KEY!; // server-side only

async function createDepositAddress(walletAddress: string) {
  const res = await fetch(`${BASE}/v1/uda`, {
    method: "POST",
    headers: { "x-api-key": KEY, "Content-Type": "application/json" },
    body: JSON.stringify({ walletAddress, market: "perps", asset: "USDC" }),
  });
  if (!res.ok) throw new Error(`UDA mint failed: ${res.status} ${await res.text()}`);
  return res.json();
}

async function getDepositQuote(body: {
  fromAmountBaseUnit: string;
  fromChainId: string;
  fromTokenAddress: string;
  recipientAddress: string;
  toChainId: string;
  toTokenAddress: string;
}) {
  const res = await fetch(`${BASE}/v1/uda/quote`, {
    method: "POST",
    headers: { "x-api-key": KEY, "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });
  if (!res.ok) throw new Error(`quote failed: ${res.status} ${await res.text()}`);
  return res.json();
}

async function getDepositStatus(walletAddress: string) {
  const res = await fetch(`${BASE}/v1/uda/status/${walletAddress}`, {
    headers: { "x-api-key": KEY },
  });
  if (!res.ok) throw new Error(`status failed: ${res.status} ${await res.text()}`);
  return res.json();
}
```

## \[Legacy] Deposit USDC via other EVM-compatible chains

The following chains are supported via Circle's CCTP: Arbitrum, Base, Avalanche C-Chain, Arc. Minimum deposit is 5 USDC. You can either generate an intent address via the front-end, or via [API](https://docs.lighter.xyz/api/bridge):

```shell
curl -X POST https://mainnet.zklighter.elliot.ai/api/v1/createIntentAddress \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "chain_id=42161&from_addr=0xyourL1address&amount=0&is_external_deposit=true"
```

Available networks can be fetched, together with their Chain ID, via the [deposit/networks](https://docs.lighter.xyz/api/bridge) endpoint.

## Withdrawals: Secure and Fast

You can process both [secure](https://github.com/elliottech/lighter-python/blob/main/examples/transfers/withdraw_normal.py), [fast withdrawals](https://github.com/elliottech/lighter-python/blob/main/examples/transfers/withdraw_fast.py), and [transfers](https://github.com/elliottech/lighter-python/blob/main/examples/transfers/transfer.py) via both SDKs, you can find linked examples with the Python SDK. The TypeScript examples below use the WASM signer and `sendTx` helper from [Signing Transactions](/developers/integration-guides/signing-transactions.md#sign-transactions).

| Operation             | Destination                             | Signatures needed               | Asset     | Minimum       | Speed                 |
| --------------------- | --------------------------------------- | ------------------------------- | --------- | ------------- | --------------------- |
| **Secure withdrawal** | The account owner's own L1 address only | API key                         | Any       | 1 USDC equiv. | Settles via Ethereum  |
| **Fast withdrawal**   | Any Ethereum address                    | API key **+ L1**                | USDC only | 4 USDC        | Fast (liquidity pool) |
| **Transfer**          | Another Lighter account                 | API key (+ L1 if another owner) | Any       | 1 USDC equiv. | Instant               |

Withdrawals and transfers have their own per-transaction-type limits; see [Rate Limits](/developers/reference/rate-limits.md#transaction-type-limits).

### Secure withdrawal

Funds can only go to the L1 address that owns the account, so the API key alone is enough.

```typescript
const tx = check(lighter.SignWithdraw(
  assetIndex,   // from /api/v1/assetDetails
  0,            // routeType: 0 = perps, 1 = spot
  amount,       // integer in the asset's Lighter decimals (USDC: 6)
  0, await nextNonce(), API_KEY_INDEX, ACCOUNT_INDEX,
));
await sendTx(tx);
```

The withdrawal is finalized on Ethereum. Lighter usually claims it for the user; if not, the user can call `withdrawPendingBalance` on the contract (see [Priority Transactions](/developers/reference/priority-transactions.md)). If you prefer, you can also process secure withdrawals from the contract directly, using the `withdraw` (0xd20191bd) method.

### Transfer between Lighter accounts

Use transfers to move funds between a user's master and sub-accounts, or to another user.

1. Get the fee: [transferFeeInfo](https://docs.lighter.xyz/api/info) (`GET /api/v1/transferFeeInfo?account_index=…&to_account_index=…`, authenticated). The fee is charged **on top** of the amount and must match exactly.
2. Sign:

```typescript
const tx = check(lighter.SignTransfer(
  toAccountIndex,
  assetIndex,
  0,               // fromRouteType: 0 perps, 1 spot
  0,               // toRouteType
  amount,          // integer, asset decimals
  fee.transfer_fee_usdc,
  "0x" + "00".repeat(32), // memo: 32 bytes
  0, await nextNonce(), API_KEY_INDEX, ACCOUNT_INDEX,
));
```

3. If the destination belongs to a **different owner** (a different master account), have the owner's wallet sign `tx.messageToSign` and set `txInfo.L1Sig` (same pattern as [ChangePubKey](https://docs.lighter.xyz/developers/integration-guides/pages/d1q7WUTUJVmxIIgcv84o#id-2.-register-an-api-key)). Transfers between the same owner's accounts need no wallet signature, even though `messageToSign` is still returned. See [When an L1 signature is required](/developers/reference/wasm-signer.md#when-an-l1-signature-is-required).
4. Send with `sendTx`.

### Fast withdrawal (USDC)

A fast withdrawal is a transfer to Lighter's fast-withdraw pool with the destination address encoded in the memo:

1. [fastwithdraw/info](https://docs.lighter.xyz/api/bridge) (`GET /api/v1/fastwithdraw/info?account_index=…`, authenticated) → `to_account_index`, `withdraw_limit`.
2. [transferFeeInfo](https://docs.lighter.xyz/api/info) for that `to_account_index`.
3. Build `memo` = destination address (20 bytes) + 12 zero bytes.
4. `SignTransfer(...)` to the pool account, collect the **L1 signature**.
5. [fastwithdraw](https://docs.lighter.xyz/api/bridge) (`POST /api/v1/fastwithdraw`) with form fields `tx_info` and `to_address`.

Reference implementation: [withdraw\_fast.py](https://github.com/elliottech/lighter-python/blob/main/examples/transfers/withdraw_fast.py).

### History

[deposit\_history](https://docs.lighter.xyz/api/transactions), [withdraw\_history](https://docs.lighter.xyz/api/transactions) and [transfer\_history](https://docs.lighter.xyz/api/transactions) return past movements. See [Historical Data](/developers/integration-guides/historical-data.md).

## Lighter on Robinhood Chain

### Deposit via Robinhood Chain

To deposit via Robinhood Chain mainnet, you can use the `deposit` method directly. You'll need to specify the following parameters:

* `_to`: the L1 address you want to credit the deposit to
* `_assetIndex`: the asset you want to deposit. You can grab the correct asset id from the [assetDetails](https://docs.lighter.xyz/api/orders) endpoint
* `_routeType`: whether you want to deposit the asset to your perps (0), or spot account (1). Only USDG can be deposited to your perps account
* `_amount`: the amount you're depositing. *it should be in line with the ERC20's decimals. E.g. 6 decimals for USDG, 18 decimals for Ether etc. 1 USDG, or equivalent, minimum.*

If you're depositing assets different from ETH (e.g. USDG), make sure to approve spending for Lighter's smart contract (0x94bAB9693Ba2f6358507eFfcbd372b0660AFfF9d) for that ERC20. There is a minimum of 1 USDG, and equivalent for other ERC20s, per deposit.

### Deposit via Robinhood Chain (intents)

An intent address is persistent, and tied to the address that generated it. It will credit USDG upon transfers, and doesn't require contract calls as the above method does. Minimum deposit is 1 USDG. You can either generate an intent address via the front-end, or via [API](https://docs.lighter.xyz/api/bridge):

```shell
curl -X POST https://api.rh.lighter.xyz/api/v1/createIntentAddress \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "chain_id=4663&from_addr=0xyourL1address&amount=0&is_external_deposit=true"
```

### Withdrawals: Secure and Fast

You can process both [secure](https://github.com/elliottech/lighter-python/blob/main/examples/transfers/withdraw_normal.py), [fast withdrawals](https://github.com/elliottech/lighter-python/blob/main/examples/transfers/withdraw_fast.py), and [transfers](https://github.com/elliottech/lighter-python/blob/main/examples/transfers/transfer.py) via both SDKs, you can find linked examples using the Python SDK. If you're processing a Fast Withdrawal (USDG only, 1 USDG minimum), or a Transfer to another address, you'll need to sign with your private key as well. If you prefer, you can process secure withdrawals from the contract directly, using the `withdraw` method. Transfers, and Secure & Fast Withdrawals all have a 1 USDG, or equivalent, minimum.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.lighter.xyz/developers/integration-guides/deposits-transfers-and-withdrawals.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
