> For the complete documentation index, see [llms.txt](https://sodex.com/documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sodex.com/documentation/for-developers/developers/mirror-protocol/lifecycle/deposits.md).

# Bridge Deposits

Call the **source-chain** bridge contract. This is not a custody transfer to an assigned address. See [Mirror Protocol Lifecycle](/documentation/for-developers/developers/mirror-protocol/lifecycle.md#deposits) for route selection and completion. Bridge addresses on Base and Ethereum are also listed on [Contracts](/documentation/for-developers/developers/mirror-protocol/contracts.md); still load `bridge.bridgeAddress` from config for the selected asset and chain.

## 1. Select the route

From [Asset Configuration](/documentation/for-developers/api-reference/mirror-api/asset-configuration.md), pick a `chains` entry where `bridge` is present and `bridge.allowDeposit` is `true`. Use that exact `chainName` in status queries (`BASE_ETH`, not `8453`).

* Source token is `chains[].tokenAddress`, not `valueChainMetadata.evmAddress`.
* Bridge is `bridge.bridgeAddress`.
* `coinSymbol` in the contract call is canonical **`assetName`** (the same string as `name=`).
* `bridge.minDepositAmount` is the amount that must arrive, in human-readable asset units. `RAW_AMOUNT` is source-token base units. Source-chain gas is extra.
* `receiver` is the user's **ValueChain EVM** address, not the paying key on the source chain (unless they are the same EOA).

## 2. Choose `toClob`

| `toClob` | Credit                                                                                                                                                                                  |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `true`   | Spot. Do not call ClobGateway `depositERC20` afterward.                                                                                                                                 |
| `false`  | ValueChain EVM. Move into Spot or Perps later with [ValueChain to Spot or Perps](/documentation/for-developers/developers/mirror-protocol/lifecycle/valuechain-transfers.md) if needed. |

If the trading account does not exist (`UserNotFound`), the first Spot credit must be USDC or SOSO. Do not use `toClob: true` with another asset as the activating deposit.

## 3. Submit on the source chain

ERC-20 path: approve the bridge to spend the source token, then `bridge(string coinSymbol, address receiver, uint256 amount, bool toClob)`.

The example below is that ERC-20 path on Base (`BASE_ETH`, chain ID 8453). The wallet needs ETH on Base for gas. On Ethereum or Arbitrum use that chain's RPC and the same `chainName` in status. Set `PRIVATE_KEY`, `COIN` (`assetName`), `TOKEN_ADDRESS`, `BRIDGE_ADDRESS`, `RECEIVER`, `RAW_AMOUNT`, and `TO_CLOB` (`true` or `false`). This broadcasts an approval and a deposit.

Save as `bridge-deposit.mts` and run `npx tsx bridge-deposit.mts`.

```typescript
import { createPublicClient, createWalletClient, http, parseAbi, type Address, type Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";

const account = privateKeyToAccount(process.env.PRIVATE_KEY as Hex);
const publicClient = createPublicClient({ chain: base, transport: http() });
const walletClient = createWalletClient({ account, chain: base, transport: http() });
const token = process.env.TOKEN_ADDRESS as Address;
const bridge = process.env.BRIDGE_ADDRESS as Address;
const receiver = process.env.RECEIVER as Address;
const coin = process.env.COIN!;
const amount = BigInt(process.env.RAW_AMOUNT!);
const toClob = process.env.TO_CLOB === "true";
const abi = parseAbi([
  "function approve(address spender, uint256 amount) returns (bool)",
  "function bridge(string coinSymbol, address receiver, uint256 amount, bool toClob)",
]);

const approval = await walletClient.writeContract({
  address: token, abi, functionName: "approve", args: [bridge, amount],
});
const approvalReceipt = await publicClient.waitForTransactionReceipt({ hash: approval });
if (approvalReceipt.status !== "success") throw new Error("Approval reverted");

const hash = await walletClient.writeContract({
  address: bridge, abi, functionName: "bridge",
  args: [coin, receiver, amount, toClob],
});
console.log({ sourceTxHash: hash });
const receipt = await publicClient.waitForTransactionReceipt({ hash });
if (receipt.status !== "success") throw new Error("Bridge deposit reverted");
```

A source-chain receipt is not ValueChain or Spot credit.

SOSO on a bridge route uses `bridgeNativeToken` with `receiver`, `amount`, and `toClob` — not the `bridge` ABI above. Take the source-token address from that chain's config; do not reuse another asset's call.

## 4. Track the deposit

Query [Deposit status](/documentation/for-developers/api-reference/mirror-api/history-and-status.md#deposit-status) with the source tx hash and the same `chainName`:

```bash
curl -sS --get "https://mainnet-gw.sodex.dev/api/v1/user/deposit/status" \
  --data-urlencode "chain=$CHAIN" \
  --data-urlencode "txHash=$SOURCE_TX_HASH" \
  -H "Accept: application/json"
```

* If `chain` does not match the record, the API returns empty, not an error.
* The same `txHash` can match several records with different `n`. Inspect every row, including `status`, `failCode`, and `failReason`.
* Empty records or `Processing` do not confirm credit.

Reconcile the intended ledger: Spot when `toClob` was `true`, otherwise the ValueChain EVM balance (native or `evmAddress`). Do not send a second bridge transaction to retry a status query.

{% content-ref url="/pages/na8o9MAsQDanoJmg0eZW" %}
[Mirror Protocol Lifecycle](/documentation/for-developers/developers/mirror-protocol/lifecycle.md)
{% endcontent-ref %}

{% content-ref url="/pages/CMCc0kXoVuQVc5eMRSUw" %}
[History & Status](/documentation/for-developers/api-reference/mirror-api/history-and-status.md)
{% endcontent-ref %}
