Skip to main content
User onboarding on Derive is fully programmatic - no humans in the loop. You can integrate the Derive Exchange for your users within minutes. Your account and first subaccount come into existence the moment a deposit is credited to your wallet on-chain.

The account model

Three terms show up throughout the API. They nest:
  • Wallet — your Ethereum EOA (the address that owns everything). One wallet ↔ one account.
  • Subaccount — the unit you actually trade from. It holds collateral and positions and is identified by a numeric subaccount_id. A wallet can own many.
  • Manager — the margin/risk model a subaccount runs under: standard (cross) margin or portfolio margin. You pick a manager when the subaccount is created; it also fixes the subaccount’s risk universe.
A brand-new wallet’s first deposit creates two subaccounts: the funded one you asked for, plus a fallback subaccount (under manager id 0) that catches any deposit that can’t be applied to its intended target. Expect two ids to appear the first time — the fallback is normal.
v3 has no private/create_subaccount method — subaccounts are created on-chain by depositing. See the changelog for the v2 → v3 method changes.

Step 1 — Choose deposit params

A deposit is routed by three choices: what asset to credit, what manager the subaccount runs under, and what risk universe it lives in. All three come from public/get_all_currencies, which needs no authentication — for each currency it lists the registered spot assets and the managers that risk-price it.

What asset

A deposit credits a protocol spot asset — the on-book balance — not the ERC-20 token you send. Read these from the currency’s spot[] entry:
A currency can register more than one spot asset (e.g. lending USDC and non-lending USDC-NL) — match the name.

What manager

The manager sets the subaccount’s margin model: managers[].sm is the Standard (cross-margin) id and managers[].pm the Portfolio-margin id. Pass your chosen id as manager_id when creating the subaccount. See Managers & risk universes for how to choose.

What risk universe

Each manager belongs to one risk universe (managers[].risk_universe_id), so choosing the manager_id also fixes the universe — the risk boundary that bounds what the subaccount can trade and hold. See Managers & risk universes.

Step 2 — Deposit

You can deposit 3 different ways - each ideal for different types of users:
  1. Direct: call the Deposit() or DepositNewSubaccount() calls on the OnchainActionManager.sol. (~2 min)
  2. Standard: less integration work as simply requires user to send funds to a custom ETH address from where a keeper will auto deposit funds into the exchange. (~2 min)
  3. Instant: fastest deposit times at ~15 seconds, with same integration simplicity to standard. Currently only supported for USDC (reach out if you’d like other collaterals) and for amounts <$1k. There also may be a small fee depending on network conditions.
Diagram of the three Derive deposit methods. Direct: call Deposit() or DepositNewSubaccount() on OnchainActionManager.sol; takes 5-15 minutes while the L1 reaches finality. Standard: send funds to a custom ETH address from which a keeper auto-deposits them into the exchange; also 5-15 minutes but needs no contract calls. Instant: send funds to a custom ETH address and the keeper fronts them directly in the exchange within 1-3 minutes; fastest, but currently USDC-only for amounts under $1,000 and charges a small fee.
Your own wallet calls the settlement contract (ACTION_MANAGER, address per Contracts). First approve the contract to pull your ERC-20, then call one of:
  • depositToNewSubaccount(asset, amount, managerId, owner) — create a new subaccount under managerId, owned by owner.
  • deposit(asset, amount, subaccountId, fallbackRecipient) — fund an existing subaccountId; fallbackRecipient receives the funds into its fallback subaccount if the deposit cannot be applied.
asset is the protocol spot asset address (spot[].address from Step 1), not the ERC-20 token. amount is in the token’s native ERC-20 decimals
Mainnet settlement-contract addresses are deployment-specific — do not hardcode them from the docs. Confirm the ACTION_MANAGER address for your target deployment on Contracts before mainnet use.

Step 3 — Confirm the deposit was credited

A mined deposit transaction is not the end of the story: the exchange credits the funds asynchronously, and the new subaccount_id is not carried in the transaction receipt. Two endpoints cover the gap.

First feedback — public/get_pending_deposits

Whichever method you used, an entry appears here the moment the exchange picks the deposit up: Direct and Standard deposits as soon as the action lands in the OnchainActionManager (for Standard, when the keeper sweeps the deposit address); Instant deposits as soon as the keeper indexes the transfer. It is a public call, so it works before your account exists. From there the paths diverge:
  • Instant deposits are processed straight from this feed — keep polling it until every entry reads credited (the lifecycle above); the SDK’s client.deposits.awaitFastDeposit does exactly that.
  • Direct / Standard deposits sit here (pendingconfirmed) while the exchange waits roughly two minutes of confirmations before including them in state — once your entry shows up, switch to polling private/get_subaccounts below.

Crediting — private/get_subaccounts

Discover a new subaccount by snapshotting your subaccount ids before depositing and polling private/get_subaccounts afterward for the id that appears — the SDK’s client.deposits.awaitNewSubaccount does this. For a deposit into an existing subaccount, poll private/get_subaccount and watch its collateral balance increase.
For Direct and Standard deposits (both observed on-chain), you can track whether the exchange has picked up your on-chain action with public/get_onchain_action_history. It lists each OnchainActionManager action the sequencer scraped and its status — applied (with an op_uuid), consumed as a fallback no-op, or still retrying. (Instant deposits are keeper-fronted and do not appear here.)
For a full record of credited Direct and Standard deposits use private/get_deposit_history, scoped to the whole wallet or a single subaccount_id. Amounts and fee are decimal strings; the net credited amount is amount - fee. Instant deposits are credited as transfers, so they do not appear here — they show up as incoming rows in private/get_erc20_transfer_history (see Transfers & Withdrawals), with their crediting lifecycle in public/get_pending_deposits.
private/get_subaccounts and private/get_deposit_history are private methods — authenticate the connection with session login first. Once a subaccount is funded, you can log in and start trading.

Next steps

Quickstart

Now that your subaccount is funded, log in, sign an order, and stream your fills.

Authentication

Session login and the per-action signing model.

Transfers & Withdrawals

Move collateral between subaccounts and back on-chain.