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

# Vault Deposits & Withdrawals

> Approve tokens, deposit wallet assets into Monaco, and withdraw available balances back on-chain.

The Monaco vault is the bridge between a user's Sei wallet and Monaco account balances. Deposits move assets into Monaco for trading. Withdrawals move available balances back on-chain.

Trading inside Monaco is gasless, but deposits and withdrawals are on-chain wallet transactions. Users still need SEI gas for those settlement actions.

## Surface Map

| Surface | Use |
| - | - |
| REST | `POST /api/v1/withdrawals`, `GET /api/v1/withdrawals/{withdrawalIndex}`, `POST /api/v1/sweeper/register`, `GET /api/v1/sweeper/chains` |
| TypeScript SDK | `sdk.vault.approve()`, `sdk.vault.needsApproval()`, `sdk.vault.deposit()`, `sdk.vault.withdraw()`, `sdk.vault.retryWithdrawal()`, `sdk.vault.getAllowance()`, `sdk.sweeper.register()`, `sdk.sweeper.getChains()` |
| React SDK | `useVault()` |
| WebSocket | `balances`, `movements` for resulting account updates |
| gRPC | `WithdrawalsService`, `SweeperService` |

## Mental Model

Wallet assets are not tradable until they enter Monaco. Deposits move assets from the connected wallet into Monaco's vault. Spot orders reserve balances from the user's Monaco spot account. Perps trades use collateral held in the user's perps account.

Withdrawals move available balances back out of Monaco. Funds locked by open orders, pending operations, or required as perps collateral cannot be withdrawn until they are released.

## Deposit Flow

<Steps>
  <Step title="Authenticate the wallet">
    Create a Monaco session for the connected wallet before calling vault methods.
  </Step>

  <Step title="Resolve the asset ID">
    Monaco vault methods use asset UUIDs. The easiest way to find an asset ID is from a trading pair's `baseAssetId` or `quoteAssetId`.
  </Step>

  <Step title="Approve the vault">
    Check whether approval is needed, then approve Monaco's vault contract to spend the ERC20 token if required.
  </Step>

  <Step title="Deposit into Monaco">
    Deposit to the spot account by default, or route directly to margin collateral when the integration is funding perps.
  </Step>
</Steps>

```typescript theme={null}
const pair = await sdk.market.getTradingPairBySymbol("BTC/USDC");
const assetId = pair.quoteAssetId;
const amount = parseUnits("100", 6);

if (await sdk.vault.needsApproval(assetId, amount)) {
  await sdk.vault.approve(assetId, amount);
}

await sdk.vault.deposit(assetId, amount);
```

Allowances are wallet-side ERC20 approvals for Monaco's vault contract. They are not Monaco account balances, but they determine whether a deposit needs an approval transaction before the deposit transaction.

```typescript theme={null}
const allowance = await sdk.vault.getAllowance(assetId);
const needsApproval = await sdk.vault.needsApproval(assetId, amount);

console.log({ allowance: allowance.toString(), needsApproval });
```

## Deposit Directly to Perps Collateral

By default, `vault.deposit()` credits the user's spot account. Pass `"margin"` as the target when you want to route the on-chain deposit directly into perps collateral.

```typescript theme={null}
const pair = await sdk.market.getTradingPairBySymbol("BTC/USDC");
const assetId = pair.quoteAssetId;
const amount = parseUnits("500", 6);

await sdk.vault.approve(assetId, amount);
await sdk.vault.deposit(assetId, amount, true, "margin");
```

If margin routing is unavailable for the asset or account, Monaco falls back to spot. Keep this visible in your UI by refreshing both [account balances](/developers/account-balances) and [perps collateral](/developers/perps-collateral) after the transaction.

## Registered Deposit Addresses

Instead of prompting a wallet through the approve → deposit flow, you can give a user a stable, deterministic deposit address and have deposits of the watched assets swept into Monaco automatically — the transfer indexer filters to the token addresses `getChains()` lists, so an unlisted ERC20 sent there is not swept. Every `(application, user, deposit target)` triple maps to one such address; `sdk.sweeper.register({ depositTarget? })` (`POST /api/v1/sweeper/register`; gRPC `SweeperService.Register`) registers it so the backend monitors the address and sweeps a watched asset once its accumulated balance reaches that asset's minimum, crediting the user — no per-deposit signature or transaction from your app. A deposit that leaves the balance below the minimum stays on the address until a later one brings it up. The call is authenticated and carries no identity of its own: the application and the credited address both come from the session, so each user registers through their own client. It is idempotent and returns the derived address immediately, so you can display and fund it before any contract exists there. `depositTarget: "margin"` asks for swept deposits to land in the parent margin account's collateral; because the target is part of the derivation, spot and margin have two different deposit addresses. As with a direct deposit, margin routing that is unavailable for the asset or account falls back to spot, so refresh both balances rather than treating a margin address as proof of collateral credit. One registration covers every chain the sweeper watches: the derived address is identical on all of them and is monitored on all of them, so the request carries no chain. `sdk.sweeper.getChains()` (`GET /api/v1/sweeper/chains`; gRPC `SweeperService.GetChains`) lists that set — per chain its EVM chain id, name, whether it is the settlement hub deposits are bridged into, and the swept assets with their token addresses, decimals, and minimum sweep amounts in raw base units. It is public, so a deposit page can show where a user may send before they have a session; a balance below an asset's minimum waits on the address until a later deposit brings the total up to it (the sweep skips a balance strictly below the minimum, so an exact-minimum total sweeps). See the [Vault SDK guide](/sdk/typescript/vault#registered-deposit-addresses) for the full request/response shape and error cases.

## Withdrawal Flow

<Steps>
  <Step title="Authenticate the wallet">
    The user must be signed in before requesting a vault withdrawal.
  </Step>

  <Step title="Resolve the asset ID">
    Use a trading pair or an existing balance row to find the Monaco asset UUID.
  </Step>

  <Step title="Check available balance">
    Compare the requested amount against `availableBalanceRaw`, not total balance. Locked funds are not withdrawable.
  </Step>

  <Step title="Withdraw to the wallet">
    Submit the withdrawal and wait for the on-chain transaction result.
  </Step>
</Steps>

```typescript theme={null}
const pair = await sdk.market.getTradingPairBySymbol("BTC/USDC");
const assetId = pair.quoteAssetId;
const balance = await sdk.profile.getUserBalanceByAssetId(assetId);
const amount = parseUnits("25", 6);

if (BigInt(balance.availableBalanceRaw) < amount) {
  throw new Error("Insufficient available Monaco balance");
}

await sdk.vault.withdraw(assetId, amount);
```

## Asset IDs

Monaco uses asset UUIDs for vault operations instead of symbols or token addresses. This prevents ambiguity when assets share symbols, appear in multiple products, or map to different contracts across networks.

Trading pairs expose the asset IDs most builders need:

```typescript theme={null}
const pair = await sdk.market.getTradingPairBySymbol("BTC/USDC");

console.log({
  baseAssetId: pair.baseAssetId,
  quoteAssetId: pair.quoteAssetId,
  baseContract: pair.baseTokenContract,
  quoteContract: pair.quoteTokenContract,
});
```

Balance rows also include `assetId` for assets the user already holds.

## Builder Checklist

* Explain that deposits and withdrawals require wallet confirmations and SEI gas.
* Use asset IDs for vault operations; do not pass token symbols to deposit or withdrawal methods.
* Refresh balances after approval, deposit, withdrawal, or retry.
* Disable withdrawals for balances locked by open orders, pending operations, or perps margin requirements.

## Related Pages

* [Account Balances](/developers/account-balances) for available, locked, and total balances.
* [Perps Collateral](/developers/perps-collateral) for margin transfers and risk buckets.
* [TypeScript Vault](/sdk/typescript/vault) for full SDK method shapes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.