> 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/valuechain-transfers.md).

# ValueChain to Spot or Perps

Move an asset that is **already on ValueChain EVM** into a Spot or Perps trading account. This is not a custody or bridge deposit. A bridge call with `toClob: true` already credits Spot and must not be followed by another `depositERC20`. To move funds back to EVM and then off-chain, use [Withdrawals](/documentation/for-developers/developers/mirror-protocol/lifecycle/withdrawals.md).

Call [ClobGateway](/documentation/for-developers/developers/valuechain-evm/contracts.md) (`0x0101010101010101010101010101010101010101` on Mainnet and Testnet). The sending wallet pays native SOSO gas. For sponsored submission of an allowlisted call, see [Transaction Relayer](/documentation/for-developers/developers/valuechain-evm/relayer.md) (Mainnet only).

## 1. Confirm the asset can trade

Load [Asset Configuration](/documentation/for-developers/api-reference/mirror-api/asset-configuration.md). The asset can enter CLOB only when `sodexMetadata` is not `null`. Use `sodexMetadata.id` when a trading API requires an asset ID. `0` is valid (USDC); do not treat it as missing.

The ERC-20 to approve is `valueChainMetadata.evmAddress`. Native SOSO has no ERC-20 address. WSOSO is a different token (`0x5050…5050`); use it only when that is the configured trading asset.

```bash
curl -sS 'https://mainnet-gw.sodex.dev/api/v1/asset/config?name=USDC' \
  -H 'Accept: application/json'

curl -sS 'https://mainnet-gw.sodex.dev/api/v1/asset/config?name=SOSO' \
  -H 'Accept: application/json'
```

For SOSO, `valueChainMetadata.isNativeToken` is `true` and `evmAddress` is omitted.

## 2. Check whether the trading account exists

```bash
curl -sS "https://mainnet-gw.sodex.dev/api/v1/user/$USER_ADDRESS/status" \
  -H "Accept: application/json"
```

If `data.status` is `UserNotFound`, the first deposit must be **USDC or SOSO**. Activating the account costs **1 USDC or 1 SOSO**. After the account exists, other assets with non-null `sodexMetadata` can be deposited. This Gateway URL is Mainnet; there is no Testnet Mirror API.

## 3. Deposit from ValueChain

ClobGateway overloads:

| Destination | Call                                                                                                                                                    |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Spot        | `depositERC20(address token, uint256 amount)` — credits the caller.                                                                                     |
| Perps       | `depositERC20(address token, uint256 amount, address recipient, uint256 destination)` with `destination = 1`. `recipient` is the trading-account owner. |

### ERC-20

Save as `trading-deposit.mts` and run `npx tsx trading-deposit.mts`. Set `PRIVATE_KEY`, `TOKEN_ADDRESS` to `valueChainMetadata.evmAddress`, `RAW_AMOUNT` in that token's base units, and `DESTINATION` to `spot` or `perps`. This broadcasts Mainnet transactions from the signer to its own trading account. The wallet needs native SOSO for gas.

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

const valuechain = defineChain({
  id: 286623, name: "ValueChain",
  nativeCurrency: { name: "SOSO", symbol: "SOSO", decimals: 18 },
  rpcUrls: { default: { http: ["https://mainnet.valuechain.xyz"] } },
});
const account = privateKeyToAccount(process.env.PRIVATE_KEY as Hex);
const publicClient = createPublicClient({ chain: valuechain, transport: http() });
const walletClient = createWalletClient({ account, chain: valuechain, transport: http() });
const token = process.env.TOKEN_ADDRESS as Address;
const depositContract = "0x0101010101010101010101010101010101010101";
const amount = BigInt(process.env.RAW_AMOUNT!);
const destination = process.env.DESTINATION;
if (destination !== "spot" && destination !== "perps") throw new Error("Set DESTINATION to spot or perps");
const abi = parseAbi([
  "function approve(address spender, uint256 allowance) returns (bool)",
  "function depositERC20(address token, uint256 amount)",
  "function depositERC20(address token, uint256 amount, address recipient, uint256 destination)",
]);
const approval = await walletClient.writeContract({
  address: token, abi, functionName: "approve", args: [depositContract, amount],
});
const approvalReceipt = await publicClient.waitForTransactionReceipt({ hash: approval });
if (approvalReceipt.status !== "success") throw new Error("Approval reverted");

const hash = destination === "spot"
  ? await walletClient.writeContract({
      address: depositContract, abi, functionName: "depositERC20", args: [token, amount],
    })
  : await walletClient.writeContract({
      address: depositContract, abi, functionName: "depositERC20",
      args: [token, amount, account.address, 1n],
    });
console.log({ transactionHash: hash });
const receipt = await publicClient.waitForTransactionReceipt({ hash });
if (receipt.status !== "success") throw new Error("Trading-account deposit reverted");
```

### Native SOSO

Do not `approve`. `token` is `0x0000000000000000000000000000000000000000` and `msg.value` must equal `amount` (18 decimals). The wallet must hold `amount` plus gas in native SOSO. WSOSO cannot be used in this call.

Save as `trading-deposit-soso.mts` and run `npx tsx trading-deposit-soso.mts`. Set `PRIVATE_KEY`, `RAW_AMOUNT` in wei, and `DESTINATION` to `spot` or `perps`.

```typescript
import { createPublicClient, createWalletClient, defineChain, http, parseAbi, zeroAddress, type Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";

const valuechain = defineChain({
  id: 286623, name: "ValueChain",
  nativeCurrency: { name: "SOSO", symbol: "SOSO", decimals: 18 },
  rpcUrls: { default: { http: ["https://mainnet.valuechain.xyz"] } },
});
const account = privateKeyToAccount(process.env.PRIVATE_KEY as Hex);
const publicClient = createPublicClient({ chain: valuechain, transport: http() });
const walletClient = createWalletClient({ account, chain: valuechain, transport: http() });
const depositContract = "0x0101010101010101010101010101010101010101";
const amount = BigInt(process.env.RAW_AMOUNT!);
const destination = process.env.DESTINATION;
if (destination !== "spot" && destination !== "perps") throw new Error("Set DESTINATION to spot or perps");
const abi = parseAbi([
  "function depositERC20(address token, uint256 amount)",
  "function depositERC20(address token, uint256 amount, address recipient, uint256 destination)",
]);

const hash = destination === "spot"
  ? await walletClient.writeContract({
      address: depositContract, abi, functionName: "depositERC20",
      args: [zeroAddress, amount], value: amount,
    })
  : await walletClient.writeContract({
      address: depositContract, abi, functionName: "depositERC20",
      args: [zeroAddress, amount, account.address, 1n], value: amount,
    });
console.log({ transactionHash: hash });
const receipt = await publicClient.waitForTransactionReceipt({ hash });
if (receipt.status !== "success") throw new Error("Trading-account deposit reverted");
```

A receipt with a block is inclusion on ValueChain; do not apply extra confirmation depth. See [Transaction Finality](/documentation/for-developers/developers/valuechain-evm/transaction-finality.md). Receipt `success` is not a trading-account credit.

## 4. Confirm the trading balance

Query the destination [Spot](/documentation/for-developers/api-reference/trading-api/rest-v1/sodex-rest-spot-api.md) or [Perps](/documentation/for-developers/api-reference/trading-api/rest-v1/sodex-rest-perps-api.md) balance before trading. That requires a funded, activated trading account and the [Trading](/documentation/for-developers/developers/trading.md) API credentials. Do not treat the EVM receipt as the Spot or Perps balance.

See [Mirror Protocol Lifecycle](/documentation/for-developers/developers/mirror-protocol/lifecycle.md) for external deposit and withdrawal flows.
