> 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.md).

# Mirror Protocol Lifecycle

State machines for deposits, custody addresses, withdrawals, and completion. Executable steps are on the linked pages. Contract addresses are on [Contracts](/documentation/for-developers/developers/mirror-protocol/contracts.md).

**Mainnet only.** Base URL: `https://mainnet-gw.sodex.dev/api/v1`. There is no Testnet Mirror API.

## Deposits

```mermaid
flowchart TD
  A["Read asset configuration"] --> B["Validate chain, allow flags and minimum amount"]
  B --> C{"Route"}
  C -->|Custody| D["Enabled address and on-chain list check"]
  C -->|Bridge| E["Resolve source token and bridge contract"]
  C -->|Already on ValueChain| K["ClobGateway deposit to Spot or Perps"]
  E --> F["Approve when required"]
  D --> G["Source-network transfer; save hash"]
  F --> G
  G --> H["Query deposit records"]
  H --> I["Confirm credit on the intended ledger"]
  I --> J["Only then trade or transfer again"]
  K --> J
```

* Custody deposits credit the user's **Spot account directly**; no ValueChain EVM-to-Spot transfer is required. The first trading-account deposit must be USDC or SOSO (activation costs 1 unit).
* Bridge credits Spot when `toClob` is `true`, otherwise ValueChain EVM. Do not follow a `toClob` deposit with `depositERC20`.
* ValueChain → Spot/Perps is not an external deposit.

Use Asset Configuration to select the route and [Deposit Status](/documentation/for-developers/api-reference/mirror-api/history-and-status.md#deposit-status) to track the saved source hash. A source-network receipt is not destination credit.

## Custody addresses

```mermaid
flowchart TD
  A["Query custody address"] --> B{"Address status"}
  B -->|Empty| C["POST create for the selected chain"]
  C --> D["Wait with bounded backoff"]
  B -->|Processing| D
  D --> A
  B -->|Enabled| E["Require address in getDepositWalletList"]
  E --> H["Then display asset, chain and address"]
  B -->|Suspicious| F["Stop: do not present or send"]
  B -->|Unknown or query error| G["Do not allow deposit"]
```

Do not reuse an address across `chainName` or asset. The address object has only `chain`, `address`, and `status` — no memo/tag field. Do not invent a tag or derive one from the user's EVM address. If the destination network requires a memo or tag and it was not supplied with the custody assignment, do not open the transfer.

See [Generate Custody Address](/documentation/for-developers/developers/mirror-protocol/generate-address.md) for creation and the SoDexTokenCustody check.

{% content-ref url="/pages/fXAuQpVLw3SIeFHTMrHO" %}
[Generate Custody Address](/documentation/for-developers/developers/mirror-protocol/generate-address.md)
{% endcontent-ref %}

{% content-ref url="/pages/DCbmDYDu17UfTnk7HVvT" %}
[Deposit Addresses](/documentation/for-developers/api-reference/mirror-api/deposit-addresses.md)
{% endcontent-ref %}

## Withdrawals

```mermaid
flowchart TD
  A["Validate chain, route type, min amount and fee"] --> B{"Funds held in"}
  B -->|Perps| C["Transfer to Spot; confirm credit"]
  B -->|Spot| D["Transfer to ValueChain EVM; confirm credit"]
  C --> D
  B -->|ValueChain EVM| E["Encode WithdrawToken: assetName, chain, receiver, route 0 or 1"]
  D --> E
  E --> F["Read permit nonce, set deadline, sign digest"]
  F --> G["POST /evm-withdraw"]
  G --> H["Save ValueChain txHash and senderNonce"]
  H --> I["Track status; switch to withdrawId when present"]
  I --> J["Confirm external destination and amount"]
```

Coin in `cmdData` is canonical `assetName`. Route type is `0` (custody) or `1` (bridge). This is the [Sponsored Withdrawal](/documentation/for-developers/api-reference/mirror-api/sponsored-withdrawal.md) API, not the [Transaction Relayer](/documentation/for-developers/developers/valuechain-evm/relayer.md).

Perps funds move through Spot before ValueChain EVM. Each hop is asynchronous and must complete before the next begins. See [Withdrawals](/documentation/for-developers/developers/mirror-protocol/lifecycle/withdrawals.md).

## History and Status

Persist source-chain hashes, the ValueChain request hash, and `withdrawId` so tracking can resume after a restart or timeout.

### Deposit status

Query with the external `chainName` and source transaction hash. One hash can produce several records (`n`). A non-empty result means Gateway observed the transaction; inspect `status` before treating funds as available. If `chain` does not match, the API returns empty, not an error.

Confirm custody credit in the user's Spot balance. For bridge deposits, confirm the Spot balance when `toClob` is `true`, or the ValueChain EVM balance when it is `false`.

### Withdrawal status

Query with `chainName` plus the ValueChain request `txHash` or `withdrawId`. Prefer `withdrawId` once it exists. Status `txHash` is not the final external-chain hash. Submission is not external completion.

History can filter by side, asset, chain, time window, and pending state. Persist `txHash`, `originTxHash`, and `withdrawId` when present.

### Completion checks

```mermaid
flowchart TD
  A["Load saved transfer identifiers"] --> B["Query status or history"]
  B --> C{"Record and outcome"}
  C -->|Missing, Processing or pending| D["Retain identifiers; retry with bounded backoff"]
  D --> B
  C -->|Unknown or query error| E["Investigate; do not resubmit"]
  C -->|Terminal failure| F["Record failure; do not mark delivered"]
  C -->|Reported success| G["Reconcile destination and amount"]
  G --> H{"Credit confirmed?"}
  H -->|Yes| I["Mark complete"]
  H -->|No| J["Keep unresolved"]
```

These branches are integration decisions, not extra API status values.

| Observation                                      | What it establishes                    | What to do next                                          |
| ------------------------------------------------ | -------------------------------------- | -------------------------------------------------------- |
| Deposit address is `Enabled`                     | API has a string.                      | Verify it in `getDepositWalletList`. Still not a credit. |
| Address is in `getDepositWalletList`             | On-chain assignment matches.           | Transfer may be opened. Still not a credit.              |
| HTTP success or envelope `code=0`                | The query or submission succeeded.     | Inspect the transfer record.                             |
| Source transaction receipt succeeds              | The source-chain transaction executed. | Keep tracking the cross-chain transfer.                  |
| Transfer is `Processing`                         | Not finished.                          | Poll; do not resubmit.                                   |
| History query uses `pending=false`               | The query asked for non-pending rows.  | The filter is not delivery.                              |
| Unknown status, missing record, or query failure | Completion is not established.         | Keep identifiers; retry the query.                       |

Do not infer arrival from a transaction hash or from the absence of pending history. A terminal failure is not delivery.

### Operational guidance

* Make status polling idempotent.
* Persist identifiers before waiting for settlement.
* Use bounded backoff and expose pending states.
* Reconcile the destination balance before retrying an ambiguous operation.

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

## Transfer guides

{% content-ref url="/pages/03B5y3G7dAKHIhvwu4W1" %}
[Custody Deposits](/documentation/for-developers/developers/mirror-protocol/lifecycle/custody-deposits.md)
{% endcontent-ref %}

{% content-ref url="/pages/t7TncsmR5dGkP0GuBsfi" %}
[Bridge Deposits](/documentation/for-developers/developers/mirror-protocol/lifecycle/deposits.md)
{% endcontent-ref %}

{% content-ref url="/pages/u4EFFgz08XReHgXj3tRV" %}
[ValueChain to Spot or Perps](/documentation/for-developers/developers/mirror-protocol/lifecycle/valuechain-transfers.md)
{% endcontent-ref %}

{% content-ref url="/pages/JQIMBpbo8FnBHw8Jnflo" %}
[Withdrawals](/documentation/for-developers/developers/mirror-protocol/lifecycle/withdrawals.md)
{% endcontent-ref %}
