Skip to content

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/trade

Request

Request Format

{
  "params": {
    "action": "voluntaryAutoExchange",
    "sourceAsset": "WETH",
    "targetUSDTAmount": "5000.0"
  },
  "nonce": 1704067200000,
  "signature": {
    "v": 28,
    "r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
  },
  "expiresAfter": 1704067300
}

Request Parameters

ParameterTypeRequiredDescription
paramsobjectYesParameters object containing action details
params.actionstringYesMust be "voluntaryAutoExchange"
params.sourceAssetstringYesCollateral asset to exchange (e.g., "WETH", "cbBTC", "sUSDe"). Cannot be "USDT"
params.targetUSDTAmountstringYesAmount of USDT to receive as a positive decimal string (e.g., "5000.0"), or "all" to exchange the entire source asset balance
nonceintegerYesPositive integer, incrementing nonce
signatureobjectYesEIP-712 signature object
expiresAfterintegerNoExpiration 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

FieldTypeDescription
sourceAssetstringCollateral asset that was exchanged
sourceAmountTakenstringAmount of source asset deducted, including the haircut
targetAssetstringAsset received (always "USDT")
targetAmountstringAmount of USDT received
indexPricestringIndex price used for the exchange
effectiveHaircutstringHaircut fraction applied (e.g., "0.01" = 1%)
collateralarrayUpdated collateral balances after the exchange
collateral[].symbolstringAsset symbol
collateral[].quantitystringRemaining 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

AssetTier (USD)Collateral Value RatioCollateral HaircutCollateral Value Addition
USDT< 500,000,000100.0%0.0%-
sUSDe0 - 5,000,00099.5%1.0%-
5,000,000 - 20,000,00099.0%3.0%25,000 USDT
20,000,000 - 50,000,00097.0%5.0%425,000 USDT
cbBTC, WETH, wstETH0 - 2,500,00099.0%1.0%-
2,500,000 - 10,000,00097.0%3.0%50,000 USDT
10,000,000 - 25,000,00095.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 CVH

Voluntary fee haircut

Voluntary Auto-Exchange Fee = lowest tier CVH

Haircut 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

  • sourceAsset must be a supported collateral type and cannot be "USDT"
  • targetUSDTAmount must 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 CodeDescriptionRetryable
UNAUTHORIZEDEIP-712 signature validation failedNo
VALIDATION_ERRORRequest validation failedNo
MISSING_REQUIRED_FIELDRequired field is missingNo
INVALID_FORMATField format is invalidNo
INVALID_VALUEInvalid parameter valueNo
RATE_LIMIT_EXCEEDEDToo many requests in time windowYes
INSUFFICIENT_MARGINNot enough margin for tradeNo
ORDER_NOT_FOUNDOrder does not existNo
OPERATION_TIMEOUTOperation timed outYes
ErrorDescription
Source asset cannot be USDTsourceAsset must be a non-USDT collateral type
Source asset is requiredsourceAsset field is missing or empty
Invalid target amounttargetUSDTAmount must be a positive decimal or "all"
Insufficient balanceAccount lacks required source asset balance including haircut
Margin violationExchange would violate minimum margin requirements