For the complete documentation index, see llms.txt. This page is also available as Markdown.

Withdrawals

Sign a WithdrawToken permit, submit it through the Sponsored Withdrawal API, and track external settlement. The user signs; Gateway pays ValueChain gas. This is not the Transaction Relayer. See Mirror Protocol Lifecycle for the funding flow.

Permit and withdrawer addresses are on Contracts: SoDexTokenCallForPermit and SoDexTokenWithdrawer.

1. Select the route

Query Asset Configuration and pick a chains entry whose custody.allowWithdraw or bridge.allowWithdraw is true. Use that exact chainName.

  • Coin in cmdData is the canonical assetName (the same string you pass as name=), not valueChainMetadata.tokenSymbol or sodexMetadata.name.

  • Route type is 0 for custody and 1 for bridge.

  • minWithdrawAmount and withdrawFee are human-readable asset units. Convert the permit amount with valueChainMetadata.tokenDecimals. An explicit fee "0" is zero; an empty fee string is unknown — do not treat it as zero.

  • The requested amount must meet minWithdrawAmount on the selected route.

2. Move funds to ValueChain EVM

The withdrawal spends the user's ValueChain EVM wallet, not a Spot or Perps balance.

Current balance
Required route

Perps

Perps → Spot → ValueChain EVM

Spot

Spot → ValueChain EVM

ValueChain EVM

No trading-account transfer

  1. Perps → Spot: signed Perps transfer with toAccountID=999 and type SPOT_WITHDRAW. Wait for Spot credit. Perps cannot transfer directly to EVM.

  2. Spot → ValueChain EVM: signed Spot transfer with toAccountID=999 and type EVM_WITHDRAW. Transfer amounts are human-readable decimal strings, not base-unit integers.

  3. Confirm the signing wallet holds at least WITHDRAW_RAW_AMOUNT in base units: native SOSO with eth_getBalance, or the ERC-20 at valueChainMetadata.evmAddress with balanceOf.

Save each transfer request ID. A successful transfer response is not EVM credit. Reconcile status and the EVM balance before retrying.

3. Encode the receiver

Receiver strings are chain-specific and case-sensitive. Take the address and any required memo/tag from the destination wallet or exchange deposit instructions. When a tag is required, set receiver to ${address}:${memo/tag} before encoding cmdData.

Keep the tag as a string; do not parse it as a number or strip leading zeros. The tag in receiver is not the sixth ABI argument (route memo). Do not move it there.

Changing the address or tag changes the signed command. Rebuild and re-sign; do not edit cmdData after signing.

4. Sign the withdrawal permit

Install viem and tsx, save as withdraw-permit.ts, and run npx tsx withdraw-permit.ts. Set USER_PK, WITHDRAW_COIN (assetName), WITHDRAW_CHAIN (chainName), WITHDRAW_RECEIVER, WITHDRAW_RAW_AMOUNT (base units), and WITHDRAW_ROUTE_TYPE (0 custody or 1 bridge). This prints the request body; it does not submit.

This flow reads nonces(owner, 0). The 15-minute deadline is an example, not a protocol maximum. The signature authorizes this withdrawal only; do not expose it.

Sign the contract-returned digest. Do not use personal_sign / signMessage or prepend the Trading API typed-signature byte. Field order is documented on Sponsored Withdrawal.

5. Submit the signed request

Save the JSON as withdrawal-request.json. Set USER_ADDRESS to the signing wallet. This broadcasts a Mainnet withdrawal.

Check envelope code as well as HTTP status. On success, persist data.txHash (the ValueChain request hash), data.senderAddress, and data.senderNonce. This is not external settlement. If the response is lost, reconcile history before sending another withdrawal.

6. Track external settlement

Query Withdrawal status starting with the returned ValueChain request hash. When a record appears, switch to its withdrawId and keep using that. Prefer withdrawId. The status txHash parameter accepts only the ValueChain request hash, not the final external-chain hash.

After withdrawId is known:

An empty result means no matching record yet, not success. If chain does not match the record, the API also returns empty. Poll the same identifier; on timeout, resume — do not submit again.

Inspect status, failCode, failReason, withdrawFee, and originTxHash in History & Status. Confirm the external destination and amount before treating the withdrawal as complete.

To list in-flight withdrawals, query history:

Last updated