Voluntary Auto Exchange
Exchange non-USDT collateral for USDT at the best available rate, with automatic haircut calculation applied to the source asset.
Endpoint
POST https://papi.synthetix.io/v1/tradeRequest
Request Format
{
"params": {
"action": "voluntaryAutoExchange",
"sourceAsset": "WETH",
"targetUSDTAmount": "5000.0"
},
"nonce": 1704067200000,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
},
"expiresAfter": 1704067300
}Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
params | object | Yes | Parameters object containing action details |
params.action | string | Yes | Must be "voluntaryAutoExchange" |
params.sourceAsset | string | Yes | Collateral asset to exchange (e.g., "WETH", "cbBTC", "sUSDe"). Cannot be "USDT" |
params.targetUSDTAmount | string | Yes | Amount of USDT to receive as a positive decimal string (e.g., "5000.0"), or "all" to exchange the entire source asset balance |
nonce | integer | Yes | Positive integer, incrementing nonce |
signature | object | Yes | EIP-712 signature object |
expiresAfter | integer | No | Expiration timestamp in seconds |
EIP-712 Type Definition
const VoluntaryAutoExchangeTypes = {
VoluntaryAutoExchange: [
{ name: "subAccountId", type: "uint256" },
{ name: "sourceAsset", type: "string" },
{ name: "targetUSDTAmount", type: "string" },
{ name: "nonce", type: "uint256" },
{ name: "expiresAfter", type: "uint256" }
]
}Response
Success Response
{
"status": "ok",
"response": {
"sourceAsset": "WETH",
"sourceAmountTaken": "2.0202",
"targetAsset": "USDT",
"targetAmount": "5000.0",
"indexPrice": "2475.0",
"effectiveHaircut": "0.01",
"collateral": [
{
"symbol": "WETH",
"quantity": "7.9798"
},
{
"symbol": "USDT",
"quantity": "15000.00"
}
]
},
"request_id": "5ccf215d37e3ae6d"
}Response Fields
| Field | Type | Description |
|---|---|---|
sourceAsset | string | Collateral asset that was exchanged |
sourceAmountTaken | string | Amount of source asset deducted, including the haircut |
targetAsset | string | Asset received (always "USDT") |
targetAmount | string | Amount of USDT received |
indexPrice | string | Index price used for the exchange |
effectiveHaircut | string | Haircut fraction applied (e.g., "0.01" = 1%) |
collateral | array | Updated collateral balances after the exchange |
collateral[].symbol | string | Asset symbol |
collateral[].quantity | string | Remaining balance of the asset |
Error Response
{
"status": "error",
"error": {
"message": "sourceAsset cannot be USDT",
"code": "VALIDATION_ERROR"
},
"request_id": "5ccf215d37e3ae6d"
}Exchange Rules
- Voluntary trader-initiated exchange with immediate execution
- Uses the best available index price at execution time
- Automatic haircut applied based on collateral tier (see table below)
- No partial fills — full target amount received or request rejected
Collateral Value Haircut
| Asset | Tier (USD) | Collateral Value Ratio | Collateral Haircut | Collateral Value Addition |
|---|---|---|---|---|
| USDT | < 500,000,000 | 100.0% | 0.0% | - |
| sUSDe | 0 - 5,000,000 | 99.5% | 1.0% | - |
| 5,000,000 - 20,000,000 | 99.0% | 3.0% | 25,000 USDT | |
| 20,000,000 - 50,000,000 | 97.0% | 5.0% | 425,000 USDT | |
| cbBTC, WETH, wstETH | 0 - 2,500,000 | 99.0% | 1.0% | - |
| 2,500,000 - 10,000,000 | 97.0% | 3.0% | 50,000 USDT | |
| 10,000,000 - 25,000,000 | 95.0% | 5.0% | 250,000 USDT |
Collateral-exchange Haircuts
If the exchange initiates a forced auto-exchange (i.e. LTV breach, USDT borrow limit breach, liquidation), a haircut will be applied to cover the related on chain costs and provide a slippage buffer/tolerance to ensure the system remains healthy.
Forced Auto-Exchange Fee = 2 * lowest tier CVHVoluntary fee haircut
Voluntary Auto-Exchange Fee = lowest tier CVHHaircut Calculation
When performing an auto-exchange for a target USDT amount, the system calculates the required source amount including haircut:
Voluntary Exchange:
sourceAmountRequired = targetUSDT / indexPrice / (1 - lowestTierCVH)
Forced Exchange:
sourceAmountRequired = targetUSDT / indexPrice / (1 - 2 * lowestTierCVH)
For example: To receive $5,000 USDT by exchanging ETH at $2,500/ETH (1% lowest tier haircut):
- Voluntary exchange:
- Source amount required: $5,000 / $2,500 / (1 - 0.01) = 2.0202 ETH
- User pays: 2.0202 ETH
- User receives: $5,000 USDT
- Forced exchange:
- Source amount required: $5,000 / $2,500 / (1 - 0.02) = 2.0408 ETH
- System takes: 2.0408 ETH
- Debt repaid: $5,000 USDT
The haircut covers slippage, operational costs, and system protection
Validation Rules
sourceAssetmust be a supported collateral type and cannot be"USDT"targetUSDTAmountmust be a positive decimal string or"all"- Account must have sufficient source asset balance including the haircut component (amount taken = targetUSDT / indexPrice / (1 - haircut))
- Exchange must maintain minimum margin requirements post-execution
Signing
All trading methods are signed using EIP-712. Each successful trading request will contain:
- A piece of structured data that includes the sender address
- A signature of the hash of that structured data, signed by the sender
For detailed information on EIP-712 signing, see EIP-712 Signing.
Nonce Management
The nonce system prevents replay attacks and ensures order uniqueness:
- Use any positive integer as nonce
- Each nonce must be greater than the previous one (incrementing)
Date.now()is a convenient option, not a requirement- If nonce conflicts occur, increment by 1 and retry
:::note SubAccountAction Exception
SubAccountAction endpoints (getPositions, getOpenOrders, getOrderHistory, getTrades, getFundingPayments, getSubAccount, getSubAccounts, getDelegatedSigners, getBalanceUpdates, getWithdrawableAmounts) do not require a nonce. Only the signature and optional expiresAfter parameters are needed.
:::
Error Handling
| Error Code | Description | Retryable |
|---|---|---|
UNAUTHORIZED | EIP-712 signature validation failed | No |
VALIDATION_ERROR | Request validation failed | No |
MISSING_REQUIRED_FIELD | Required field is missing | No |
INVALID_FORMAT | Field format is invalid | No |
INVALID_VALUE | Invalid parameter value | No |
RATE_LIMIT_EXCEEDED | Too many requests in time window | Yes |
INSUFFICIENT_MARGIN | Not enough margin for trade | No |
ORDER_NOT_FOUND | Order does not exist | No |
OPERATION_TIMEOUT | Operation timed out | Yes |
| Error | Description |
|---|---|
| Source asset cannot be USDT | sourceAsset must be a non-USDT collateral type |
| Source asset is required | sourceAsset field is missing or empty |
| Invalid target amount | targetUSDTAmount must be a positive decimal or "all" |
| Insufficient balance | Account lacks required source asset balance including haircut |
| Margin violation | Exchange would violate minimum margin requirements |
