# Token Conversions

Token conversion reallocates balance between compatible USD-equivalent tokens in one subaccount. It does not transfer an ERC-20 token or change the total backed balance. Conversions settle 1:1 in D9 units with no conversion fee.

## Why Isolated Margin Needs Conversion

Meridian calculates collateral, equity, and liquidation separately for each quote-token pool within a subaccount. Cross-margin products share the concrete USD token, MeridianUSD. Isolated products use a synthetic quote token backed by that concrete token. See [Isolated Margin](/trading/perpetual-futures/margining#isolated-margin) for how these pools work.

Depositing MeridianUSD funds the concrete USD pool. To trade an isolated product, you must explicitly convert some of that balance into the product's quote token. A balance in another pool does not automatically support the isolated position. Converting back removes collateral from that pool and makes it available in the destination pool once settled.

The isolation boundary is the quote token: products sharing a quote token share its collateral and liquidation state. Resolve the product's `marginMode` and `quoteTokenAddress` through `GET /v1/product` rather than assuming every product has a unique pool.

## Valid Paths

* A concrete token to a synthetic token backed by it.
* A synthetic token to its concrete backing token.
* Two synthetic tokens with the same concrete backing token.

Use `GET /v1/token` to resolve each token's `id`, `address`, and `backingTokenId`. A synthetic token's `backingTokenId` matches its concrete parent's `id`; two compatible synthetic tokens have the same non-null `backingTokenId`. Submit accounting addresses as `fromToken` and `toToken`, not token UUIDs or market base-token addresses.

Converting a token to itself or to an unrelated token is rejected. Synthetic-to-synthetic conversion can go directly between compatible pools without an intermediate conversion to MeridianUSD. See [Supported Tokens](/developer-guides/trading-api/supported-tokens) for token types and address conventions.

## Examples

Assume isolated quote tokens A and B are both backed by MeridianUSD, and the amounts below are available to convert.

* **Fund or top up a pool:** Convert 300 of your 1,000 MeridianUSD to A. You now have 700 MeridianUSD and 300 A to support products using A.
* **Move collateral between pools:** Convert 100 A to B. The A pool loses 100 units of collateral and the B pool gains 100.
* **Withdraw:** Isolated quote tokens cannot be withdrawn. Convert them back to MeridianUSD first, then [withdraw](/developer-guides/trading-api/token-transfers).

## Submit a Conversion

```http
POST /v1/token/convert
```

Sign and submit a `ConvertToken` EIP-712 message:

```json
{
  "data": {
    "sender": "0xSIGNER_ADDRESS",
    "subaccount": "0xBYTES32_SUBACCOUNT",
    "fromToken": "0xSOURCE_TOKEN_ADDRESS",
    "toToken": "0xDESTINATION_TOKEN_ADDRESS",
    "amount": "100.5",
    "nonce": "1785811200000000000",
    "signedAt": 1785811200
  },
  "signature": "0xEIP712_SIGNATURE"
}
```

* Get `fromToken` and `toToken` from `data[].address` in the `GET /v1/token` response. To fund an isolated market, use its backing token as the source and its `quoteTokenAddress` from `GET /v1/product` as the destination. Reverse them to convert back.
* `sender` is the owner EOA or an active linked signer authorized to perform conversions for the subaccount. EIP-1271 contract-wallet signatures are not supported.
* `amount` is a positive decimal string with up to 9 decimal places. For example, sign `100.5` as the D9 integer `100500000000`.
* Replace the example `nonce` and `signedAt` with fresh values in nanoseconds and seconds, respectively.

The signed subaccount is a bytes32 name; status queries use its UUID. See [Message Signing](/developer-guides/trading-api/message-signing) for wallet setup, nonce handling, and encoding details.

## Status and Settlement

A successful request returns `201` with the conversion ID, status, subaccount ID, token addresses, amount, fee, and creation time. The initial status is `SUBMITTED`. Track it with:

```http
GET /v1/token/transfer?subaccountId=SUBACCOUNT_UUID&types=CONVERT&orderBy=createdAt&order=desc
```

`COMPLETED` means the source debit and destination credit have settled. Wait for this status and refresh balances before placing a dependent order or withdrawing. `REJECTED` means no conversion was applied.

Match the returned conversion ID against transfer history, or track `TokenTransfer` events with type `CONVERT` through [WebSockets](/developer-guides/trading-api/websockets). If a request times out, check history before submitting another conversion to avoid moving funds twice.

## Notes and Considerations

* **Keep enough collateral in the source pool.** Positions and open orders may still need it. Moving collateral to another pool does not protect the source pool.
* **Check available balance.** Outstanding funding, position fees, and unrealized losses affect what you can convert. Unrealized price profits are not convertible, and balances can change before a request completes.
* **Handle failures before retrying.** For insufficient balance, refresh `GET /v1/subaccount/balance` and reduce the amount if needed. For signature or nonce errors, check the signer, signing configuration, and timestamps before signing again.
* **Plan around limits.** The default quota is 10 conversions per subaccount in a rolling day, including recorded conversions that later fail. See [System Limits](/developer-guides/trading-api/system-limits) for quotas and retry guidance.
