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:
- Ask for the transaction:
POST /api/relayorPOST /api/withdraw-nowanswers{ "transaction": "<base64>" }. - Sign it with the wallet (sign only, do not send) and
POST /api/relay/submitit; the answer is its signature. - 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/relaywith{ "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-nowwith{ "amount": 25 }(andtofor another Solana wallet), then sign and submit.- The withdrawal fee (1 USDC,
accountFeein the answer) comes out of the amount; it also opens a USDC account for a destination that has none. - With
networkandtokenthe USDC goes on through a bridge to another network;POST /api/withdraw/quotetells 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: 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.
/api/fundsThe chain facts a client needs
curl "https://seeryx.com/api/funds"{
"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.
/api/funds/walletUSDC in your wallet, your cash in the program, USDC on its way
| Field | Type | Description |
|---|---|---|
fresh | 1 | Skip the 5-second cache |
curl "https://seeryx.com/api/funds/wallet" \
-H "X-Auth-Token: $TOKEN"{ "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.
| Status | When |
|---|---|
| 502 | Solana could not be read; never a zero |
/api/funds/refreshAfter a deposit or withdrawal: read the program now
curl -X POST "https://seeryx.com/api/funds/refresh" \
-H "X-Auth-Token: $TOKEN"{ "ok": true }/api/relayPrepare a transaction of yours for the wallet to sign
| Field | Type | Description |
|---|---|---|
action | string | deposit, session, close_session, request_withdraw, cancel_withdraw or execute_withdraw |
amount | number | deposit, request_withdraw: USDC |
key | string | session: the new session key; close_session: the session key when it signs instead of the wallet |
expiresAt | number | session: Unix seconds, at most maxSessionTtl from now |
limit | number | session: USDC it may spend in total |
maxTrade | number | session: USDC one order may spend, at most limit |
to | string | execute_withdraw: another Solana wallet that has a USDC account |
curl -X POST "https://seeryx.com/api/relay" \
-H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"deposit","amount":10}'{ "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.
| Status | When |
|---|---|
| 400 | A 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 |
/api/relay/submitSend a prepared transaction after your wallet signed it
| Field | Type | Description |
|---|---|---|
transaction | string | base64: the transaction from /relay or /withdraw-now with your wallet's signature |
curl -X POST "https://seeryx.com/api/relay/submit" \
-H "X-Auth-Token: $TOKEN"{ "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).
| Status | When |
|---|---|
| 400 | Not a transaction prepared for your account in the last 5 minutes, or already sent |
| 409 | Its blockhash expired before it reached Solana: prepare it again |
/api/withdraw-nowAn immediate withdrawal, for the wallet to sign
| Field | Type | Description |
|---|---|---|
amount | number | USDC leaving your account, the withdrawal fee included |
to | string | Another Solana wallet, or an address on network |
network | string | With token: deliver on another network (a network of /deposit/options with withdraw true) |
token | string | USDC or USDT |
cancelPending | boolean | Replace a waiting delayed withdrawal |
curl -X POST "https://seeryx.com/api/withdraw-now" \
-H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"amount":25}'{ "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 }.
| Status | When |
|---|---|
| 400 | The amount is not above the fee, or more than your free cash |
| 409 | One of your trades is still settling: try again in a few seconds, or use a delayed withdrawal |
/api/withdraw/quoteWhat a withdrawal to another network delivers
| Field | Type | Description |
|---|---|---|
amount | number | USDC leaving your account |
network | string | A network of /deposit/options |
token | string | USDC or USDT |
to | string | Optional destination address |
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"}'{ "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.
/api/deposit/optionsNetworks and tokens a deposit can come from
curl "https://seeryx.com/api/deposit/options"{ "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.
/api/deposit/addressYour own deposit address for a token on a network
| Field | Type | Description |
|---|---|---|
network | string | A network of /deposit/options |
token | string | USDT or USDC |
curl -X POST "https://seeryx.com/api/deposit/address" \
-H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"network":"solana","token":"USDC"}'{ "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.
| Status | When |
|---|---|
| 409 | The route is not available |
| 502 | The bridge cannot be reached |
/api/deposit/recoverFind a deposit sent with another token or on another network
curl -X POST "https://seeryx.com/api/deposit/recover" \
-H "X-Auth-Token: $TOKEN"{ "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.
| Status | When |
|---|---|
| 429 | More than 2 calls a minute |