home

Guides

Deposits and withdrawals

Move USDC on Solana in and out of a Seeryx account from code: deposits, deposit addresses, instant and delayed withdrawals, and what each costs.

Overview

Your cash is USDC on Solana in your own account of the Seeryx program. Deposits and withdrawals are transactions of your wallet that the server prepares with Seeryx as the fee payer: the wallet signs, Seeryx adds its signature and sends it, so the wallet needs no SOL. Every flow is three calls:

  1. Ask for the transaction: POST /api/relay or POST /api/withdraw-now answers { "transaction": "<base64>" }.
  2. Sign it with the wallet (sign only, do not send) and POST /api/relay/submit it; the answer is its signature.
  3. Wait until Solana confirms it, then POST /api/funds/refresh: your cash follows within seconds.

sendPrepared in chain.ts (send_prepared in chain.py) does steps 2 and 3.

Deposit from the wallet

  • POST /api/relay with { "action": "deposit", "amount": 10 }, then sign and submit.
  • The deposit fee (1 USDC) is paid in the same transaction and the rest is credited.
  • Your first deposit opens your account: it must leave at least 1 USDC after the fee. Until then a trading session answers 409 "Deposit first".

Deposit address

POST /api/deposit/address with { "network": "solana", "token": "USDC" } gives you an address of your own. USDC sent there from an exchange or any wallet is added to your balance by itself (auto: true), less the deposit fee. GET /api/deposit/options lists the other networks and tokens (USDT and USDC on Ethereum, BNB Chain, Base, Polygon, Arbitrum and more), each with its minimum; those arrive through a bridge. GET /api/funds/wallet shows what is incoming.

Withdraw at once

  • POST /api/withdraw-now with { "amount": 25 } (and to for another Solana wallet), then sign and submit.
  • The withdrawal fee (1 USDC, accountFee in the answer) comes out of the amount; it also opens a USDC account for a destination that has none.
  • With network and token the USDC goes on through a bridge to another network; POST /api/withdraw/quote tells first what arrives.
  • 409 while one of your trades is still settling: try again a few seconds later.

Delayed withdrawal

Free, and signed by your wallet alone: POST /api/relay with { "action": "request_withdraw", "amount": 25 }, wait withdrawDelay seconds of GET /api/funds (60), then execute_withdraw pays the amount out to your wallet (or to, a wallet that already has a USDC account). cancel_withdraw drops the request.

Code

funds.ts
// funds.ts: deposit USDC from the wallet and withdraw it again; the exchange pays every fee. npx tsx funds.ts
import { api, loadWallet, signIn } from './seeryx';
import { sendPrepared, type Funds } from './chain';
import { logValue } from './api-url.mjs';

const wallet = await loadWallet();
await signIn(wallet);
const funds = await api<Funds>('/funds');
if (funds.mode !== 'chain') throw new Error('This server holds no USDC on Solana');

// USDC in the wallet, not deposited yet; `account` is null until the first deposit opens it
console.log({ wallet: await api('/funds/wallet') });

// deposit 10 USDC (the first deposit is at least 1): the server prepares the transaction, the wallet signs it
const deposit = await api<{ transaction: string }>('/relay', {
  method: 'POST', body: { action: 'deposit', amount: 10 },
});
console.log('deposit', logValue(await sendPrepared(funds, wallet, deposit.transaction)));
await api('/funds/refresh', { method: 'POST' }); // read the program now; cash follows within seconds
await new Promise((r) => setTimeout(r, 5000));
console.log({ balance: await api('/balance') });

// withdraw 4 USDC at once to this wallet (or `to`: another Solana wallet), co-signed by the exchange
const withdrawal = await api<{ transaction: string; accountFee: number }>('/withdraw-now', {
  method: 'POST', body: { amount: 4 },
});
const sent = await sendPrepared(funds, wallet, withdrawal.transaction);
console.log('withdrawal', logValue(sent), 'withdrawal fee', Number(withdrawal.accountFee));
await api('/funds/refresh', { method: 'POST' });

All fees in one place: Fees.

Funds endpoints

Your USDC sit in your own account of the Seeryx program on Solana. Each transaction of yours is prepared by the server with Seeryx paying the network fee: your wallet only signs.

GET/api/funds

The chain facts a client needs

Public
Request
curl "https://seeryx.com/api/funds"
Response
{
  "mode": "chain", "cluster": "mainnet",
  "programId": "2uUbvYHqBH1HDVzABGPcqrjHodoBVcNkq6Nrv6MABaiv", "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "withdrawDelay": 60, "maxSessionTtl": 86400, "instantWithdraw": true, "withdrawFee": 1.0, "depositFee": 1.0,
  "onChainTrading": true, "fees": { "rateBps": 700, "rebateBps": 2000 },
  "relayed": true, "directDeposits": true, "finePrices": true, "budgetBuys": true, ...
}
  • programId: the Seeryx program (market accounts are derived from it); mint: USDC. onChainTrading: every order, split and merge must be signed. relayed: Seeryx pays the network fee of your transactions.
  • finePrices: limits in tenths of a cent below 1¢ and above 99¢. budgetBuys: market buys are signed by budget (PMO4). maxSessionTtl: the longest trading session, in seconds; withdrawDelay: the wait of a delayed withdrawal, in seconds. depositFee and withdrawFee in USDC.
GET/api/funds/wallet

USDC in your wallet, your cash in the program, USDC on its way

Signed inSolana
FieldTypeDescription
freshqueryoptional1Skip the 5-second cache
Request
curl "https://seeryx.com/api/funds/wallet" \
  -H "X-Auth-Token: $TOKEN"
Response
{ "wallet": 200, "account": null, "sol": 0, "incoming": 0 }
  • wallet: USDC in the wallet not deposited yet. account: cash in the program, null until the first deposit opens it. incoming: USDC that reached your deposit address and is on its way to your balance.
StatusWhen
502Solana could not be read; never a zero
POST/api/funds/refresh

After a deposit or withdrawal: read the program now

Signed inSolana
Request
curl -X POST "https://seeryx.com/api/funds/refresh" \
  -H "X-Auth-Token: $TOKEN"
Response
{ "ok": true }
POST/api/relay

Prepare a transaction of yours for the wallet to sign

Signed inSolana
FieldTypeDescription
actionbodyrequiredstringdeposit, session, close_session, request_withdraw, cancel_withdraw or execute_withdraw
amountbodyoptionalnumberdeposit, request_withdraw: USDC
keybodyoptionalstringsession: the new session key; close_session: the session key when it signs instead of the wallet
expiresAtbodyoptionalnumbersession: Unix seconds, at most maxSessionTtl from now
limitbodyoptionalnumbersession: USDC it may spend in total
maxTradebodyoptionalnumbersession: USDC one order may spend, at most limit
tobodyoptionalstringexecute_withdraw: another Solana wallet that has a USDC account
Request
curl -X POST "https://seeryx.com/api/relay" \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"action":"deposit","amount":10}'
Response
{ "transaction": "AQAB..." }
  • transaction is a base64 v0 transaction with Seeryx as the fee payer and every signature slot empty. Sign it with the wallet (sign only, do not send it), then POST it to /api/relay/submit.
  • Every deposit pays the deposit fee (depositFee of GET /api/funds) in the same transaction; the rest is credited. A first deposit must leave at least 1 USDC after the fee: it opens your account.
  • close_session cancels your resting orders and stops the session key at once (its orders get trading_paused), even before the transaction is sent.
StatusWhen
400A missing or invalid field, a deposit not above the fee
409"Deposit first" (no account yet), no withdrawal waiting or not ready yet, no USDC account at the destination
POST/api/relay/submit

Send a prepared transaction after your wallet signed it

Signed inSolana
FieldTypeDescription
transactionbodyrequiredstringbase64: the transaction from /relay or /withdraw-now with your wallet's signature
Request
curl -X POST "https://seeryx.com/api/relay/submit" \
  -H "X-Auth-Token: $TOKEN"
Response
{ "signature": "5VERv8NM..." }
  • Seeryx adds its own signature, checks every signature and sends the transaction to Solana; signature is its id. Wait for confirmation with any Solana RPC (getSignatureStatuses).
StatusWhen
400Not a transaction prepared for your account in the last 5 minutes, or already sent
409Its blockhash expired before it reached Solana: prepare it again
POST/api/withdraw-now

An immediate withdrawal, for the wallet to sign

Signed inSolana
FieldTypeDescription
amountbodyrequirednumberUSDC leaving your account, the withdrawal fee included
tobodyoptionalstringAnother Solana wallet, or an address on network
networkbodyoptionalstringWith token: deliver on another network (a network of /deposit/options with withdraw true)
tokenbodyoptionalstringUSDC or USDT
cancelPendingbodyoptionalbooleanReplace a waiting delayed withdrawal
Request
curl -X POST "https://seeryx.com/api/withdraw-now" \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"amount":25}'
Response
{ "transaction": "AQAB...", "accountFee": 1 }
  • Sign the transaction with the wallet and send it through /api/relay/submit. accountFee is the withdrawal fee, taken from the amount. With network and token the answer also has bridge { receive, fee, seconds }.
StatusWhen
400The amount is not above the fee, or more than your free cash
409One of your trades is still settling: try again in a few seconds, or use a delayed withdrawal
POST/api/withdraw/quote

What a withdrawal to another network delivers

Signed inSolana
FieldTypeDescription
amountbodyrequirednumberUSDC leaving your account
networkbodyrequiredstringA network of /deposit/options
tokenbodyrequiredstringUSDC or USDT
tobodyoptionalstringOptional destination address
Request
curl -X POST "https://seeryx.com/api/withdraw/quote" \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"amount":20,"network":"base","token":"USDC"}'
Response
{ "receive": 18.89, "fee": 0.11, "networkFee": 0.11, "bridgeFee": 1, "seconds": 1 }
  • bridgeFee is the withdrawal fee; networkFee the cost of the other network's bridge, an estimate.
GET/api/deposit/options

Networks and tokens a deposit can come from

PublicSolana
Request
curl "https://seeryx.com/api/deposit/options"
Response
{ "routes": [{ "network": "solana", "token": "USDC", "min": 1, "available": true, "reason": null, "direct": true, "auto": true, "withdraw": true },
  { "network": "bsc", "token": "USDT", "min": 3, "available": true, "reason": null, "direct": false, "auto": true, "withdraw": true }, ...] }
  • direct: USDC on Solana, no bridge. auto: what arrives at your deposit address is added to your balance by itself. withdraw: a withdrawal can deliver there.
POST/api/deposit/address

Your own deposit address for a token on a network

Signed inSolana
FieldTypeDescription
networkbodyrequiredstringA network of /deposit/options
tokenbodyrequiredstringUSDT or USDC
Request
curl -X POST "https://seeryx.com/api/deposit/address" \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"network":"solana","token":"USDC"}'
Response
{ "network": "solana", "token": "USDC", "address": "7xKXtg2C...", "min": 1, "direct": true, "auto": true }
  • The same address each time for your wallet and route. Send at least min.
StatusWhen
409The route is not available
502The bridge cannot be reached
POST/api/deposit/recover

Find a deposit sent with another token or on another network

Signed inSolana
Request
curl -X POST "https://seeryx.com/api/deposit/recover" \
  -H "X-Auth-Token: $TOKEN"
Response
{ "found": [{ "address": "0x09a3...", "network": "ethereum", "token": "USDC", "amount": "25000000" }] }
  • For USDC sent to the address shown for USDT, or to an address on another network than it was made for: the bridge looks again and forwards what it finds. amount is in the token's smallest units.
StatusWhen
429More than 2 calls a minute