post https://sandbox.kyan.sh/withdraw
Withdraw USDC funds from a specific margin account back to your wallet. The system performs comprehensive risk checks to ensure your account remains healthy after the withdrawal.
Risk Checks and Requirements
Before approving a withdrawal, the system verifies:
-
Sufficient Equity: Your remaining equity must exceed both:
- Initial Margin (IM): Required for opening new positions
- Maintenance Margin (MM): Minimum to avoid liquidation
-
Account Status:
- Account must not be flagged for liquidation
- No pending settlements that would affect equity
-
Available Balance:
- Can only withdraw truly "free" collateral
- System accounts for unrealized losses on open positions
How Withdrawals Work
- You sign an EIP-712 message requesting the withdrawal
- Risk engine checks your account will remain solvent
- System approves and executes the on-chain transfer
- USDC arrives in your specified wallet address
Important Considerations
- Isolated Margins: Each trading pair has separate collateral
- Mark-to-Market: Unrealized P&L affects available withdrawal amount
- Gas Costs: On-chain withdrawal incurs network fees (paid by protocol)
- Processing Time: Usually instant, but may take a few blocks
Common Rejection Reasons
- "Insufficient equity - mm": Withdrawal would put account below maintenance margin
- "Insufficient equity - im": Withdrawal would put account below initial margin
- "Account in liquidation": Account is already flagged for liquidation
- "Margin account not found": No active account for the specified pair
Best Practices
- Check account state before withdrawing to see available balance
- Leave buffer above minimum margins to avoid liquidation
- Consider market volatility - your equity can change rapidly
- Withdraw from accounts with no open positions first
EIP-712 Signature Example (TypeScript)
import { parseUnits } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
// Domain parameters for EIP-712 signature
const EIP712Domain = {
chainId: 421614, // Arbitrum Sepolia (use 42161 for Arbitrum One mainnet)
name: 'Premia',
verifyingContract: '0x...' // ClearingHouseProxy address from deployment
version: '1'
};
// Type definitions
const Pair = [
{ name: 'base', type: 'address' },
{ name: 'quote', type: 'address' }
];
const UserWithdraw = [
{ name: 'deadline', type: 'uint256' },
{ name: 'to', type: 'address' },
{ name: 'from', type: 'address' },
{ name: 'amount', type: 'uint256' },
{ name: 'pair', type: 'Pair' }
];
// Example withdrawal data
const withdraw = {
to: '0xYourWalletAddress', // Destination EOA wallet address
from: '0xYourSmartAccount', // Smart account address
amount: 500, // Amount to withdraw
pair: {
base: '0xBaseTokenAddress', // e.g., WETH address
quote: '0xQuoteTokenAddress' // e.g., USDC address
}
};
// Calculate deadline (30 seconds from now)
const deadline = Math.floor(Date.now() / 1000) + 30;
// Setup wallet
const account = privateKeyToAccount('0xYourPrivateKey');
// Sign the typed data
const signature = await account.signTypedData({
domain: EIP712Domain,
types: {
UserWithdraw,
Pair
},
primaryType: 'UserWithdraw',
message: {
deadline,
to: withdraw.to,
from: withdraw.from,
amount: parseUnits(withdraw.amount.toString(), 6),
pair: withdraw.pair
}
});
// Final request payload
const requestPayload = {
...withdraw,
signature,
signature_deadline: deadline
};