available balance and is
required collateral for placing BUY orders. It is always authorised by
the EOA owner — neither the platform nor a partner API key can move
funds out of an EOA without the owner’s authorisation, whether that’s a
user-sent depositERC20 transaction or a signed
EIP-2612 permit relayed on the user’s
behalf.
There are two ways to deposit:
- Direct (self-paid) — the EOA
approves the vault once, then sendsdepositERC20itself. The user pays gas. Walkthrough below. - Gasless (relayed permit) — the user signs an EIP-2612
USDC.permitoff-chain and the platform broadcasts the deposit; no gas, no separateapprove. See Gasless deposit.
Prerequisites
End-to-end flow
Step 1 — approve (once per vault)
MaxUint256 saves gas on every future deposit. Tighten to a per-deposit
allowance if your security model requires it — the trade-off is one
extra approve per deposit.
Step 2 — depositERC20
transferFrom(eoa → vault), increments
its internal collateral ledger by amount, and checks the deposit-cap
windows in DepositLimitRegistry before settling. If the cap would be
exceeded, the tx reverts with DepositCapExceeded() — see
Deposit limits.
Step 3 — wait for the platform to credit
After the deposit tx mines, the platform indexes the on-chain event and creditsexchange.balances.available for your associated EOA.
End-to-end latency from mined tx to credited balance is typically
well under 1 second on testnet (chain-watcher streams events
sub-second) and a few seconds on mainnet (indexer batches
confirmations into the ledger). Plan UI for the mainnet ceiling — the
testnet path is faster than partners typically expect, so build for
the slower target and treat the testnet behaviour as the optimistic
case.
Two ways to observe it:
Gasless deposit (relayed permit)
Retail / embedded-wallet users — and partners holding thevault:write
scope — can deposit without native gas and without a separate
approve. Instead of sending depositERC20 yourself, you sign an
EIP-2612 USDC.permit
off-chain and the platform broadcasts the on-chain deposit for you.
- Read
multicallExecutorfromGET /api/platform/contractsand the user’sUSDC.nonces(owner)from chain. - Build the
PermitTypedData — domain is the deployed USDC contract (name,version,chainId,verifyingContract= USDC address); message is{ owner, spender: multicallExecutor, value: amount, nonce, deadline }. Sign witheth_signTypedData_v4. POST /api/deposits/relaywith the rawamount(6-decimal units),permitNonce, apermitDeadlinethat leaves the relayer a comfortable buffer, and the split signature(v, r, s). Response:{ auditId, jobId, status }.- Poll
GET /api/deposits/relay/{auditId}untilstatus: "CONFIRMED"(PENDING_SCREENING → SUBMITTED → CONFIRMED; terminal statesREJECTED/REVERTED/EXPIRED).
The permit signature is the authorization — the backend
ecrecovers
it and requires the signer to equal the authenticated wallet, so no
on-chain approve is needed and a partner cannot forge a user’s deposit.
Common rejections: permit_deadline_passed, permit_deadline_too_soon,
permit_nonce_mismatch, permit_signer_mismatch, tier_cap_exceeded,
restriction_active. The auditId is returned even on failure so you can
reference it in support tickets.Idempotency and replays
Deposits are uniquely keyed by their on-chain(txHash, logIndex).
If you receive the same vault.deposit_confirmed event twice (network
retry, WS reconnect with replay), the platform credits the deposit
exactly once — replays are cheap no-ops. Safe to handle naively.
Withdrawing later
Funds in the vault stay liquid — withdraw any time via the dual-signed flow documented in Withdrawals overview. The vault also exposes a 7-day-timelocked emergency withdraw for recovery if the platform is unavailable; see Vault contract reference.Common failures
Next
Deposit limits
Daily / weekly / monthly caps and how rolling windows are applied.
Withdrawals overview
Dual-signature flow, AML review, state machine.
Place your first order
Sign + POST a vault-backed order against any open market.
Vault contract reference
Full ABI for the vault, including the deposit entry point.