DeepBook Fees and Funding
DEEP pays DeepBook trading fees. Before placing fee-paying orders, you fund a BalanceManager with DEEP, and optionally stake DEEP to reduce your fees. You can also pay fees with the input token instead of DEEP.
The TypeScript samples on this page live in the examples/deepbook-spot package and type-check with tsc --noEmit against @mysten/deepbook-v3 and @mysten/sui. They reference pools and coins by SDK key (for example DEEP_SUI, SUI_DBUSDC, DEEP) rather than hardcoding onchain IDs. See the DeepBookV3 SDK constants for the key-to-ID mapping and Contract Information for the canonical IDs.
Pay fees in DEEP or the input token
You choose the fee asset per order with the pay_with_deep flag (the SDK's payWithDeep, default true):
- DEEP (default): the pool prices the fee in DEEP from its onchain DEEP price.
- Input token: the pool charges the fee in the asset you trade, at 25% more than the DEEP-denominated fee (equivalently, DEEP is about 20% cheaper). This penalty is the
FEE_PENALTY_MULTIPLIERconstant.
Both paths work for orders and swaps. In pool.move, place_order_int selects get_order_deep_price when pay_with_deep is true and empty_deep_price otherwise, with no assertion forcing either. One older note in the reference (place_limit_order says pay_with_deep must be true) predates input-token fees, which shipped in package version 2; treat payWithDeep as a free choice.
Paying in DEEP requires the pool to have a DEEP price point. Established pools have one. A brand-new permissionless pool can only charge input-token fees until an operator adds a price point from a reference pool. Input-token fees always work.
How the DEEP fee is sized
The DEEP fee is not a fixed number. Each pool stores a DeepPrice object holding up to 100 recent conversion-rate points between the pool's asset and DEEP, sourced from a whitelisted DEEP/USDC or DEEP/SUI reference pool. The pool divides the cumulative rate by the number of points to get deep_per_asset, then multiplies by your trade size. See Design for the vault and pricing model.
Because this rate floats, read the DEEP a trade needs at execution time rather than hardcoding it. The SDK's getQuantityOut returns the DEEP required alongside the output amounts:
import type { DeepBookTestnetClient } from './client.js';
// How much DEEP a trade needs comes from the pool's floating DEEP price, so it
// cannot be hardcoded. `getQuantityOut` returns the base out, quote out, and the
// DEEP required for the requested quantity. Pass a nonzero base OR quote amount.
export async function readDeepRequired(
client: DeepBookTestnetClient,
poolKey: string,
baseQuantity: number,
quoteQuantity: number,
) {
const result = await client.deepbook.getQuantityOut(poolKey, baseQuantity, quoteQuantity);
return result; // { baseOut, quoteOut, deepRequired }
}
Maker, taker, and staking fees
Maker fee, taker fee, and the stake requirement are per-pool governance parameters (TradeParams), not constants. Governance can change them, so read them onchain instead of hardcoding:
import type { DeepBookTestnetClient } from './client.js';
// Taker fee, maker fee, and stake requirement are per-pool governance
// parameters. Read them on-chain instead of hardcoding, because governance can
// change them. Fees are returned in billionths (divide by 1e9 for a fraction).
export async function readPoolFees(client: DeepBookTestnetClient, poolKey: string) {
const params = await client.deepbook.poolTradeParams(poolKey);
return params; // { takerFee, makerFee, stakeRequired }
}
Design lists the fee bounds for volatile, stable, and whitelisted pools. Staking DEEP reduces your taker fee: when your active stake and your volume in DEEP both meet the pool's stake requirement, the pool halves your taker fee.
packages/deepbook/sources/state/trade_params.move. You probably need to run `pnpm prebuild` and restart the site.Staking also earns maker rebates. See Staking and Governance for staking, rebates, and proposals.
Fund a BalanceManager with DEEP
Deposit DEEP into your BalanceManager so orders can pay fees from it. The same DEEP balance is what you stake for the fee discount. Every sample on this page shares the client setup:
import { SuiGrpcClient } from '@mysten/sui/grpc';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { decodeSuiPrivateKey } from '@mysten/sui/cryptography';
import { deepbook, type DeepBookClient, type BalanceManager } from '@mysten/deepbook-v3';
import type { ClientWithExtensions } from '@mysten/sui/client';
export type DeepBookTestnetClient = ClientWithExtensions<{ deepbook: DeepBookClient }>;
export function getKeypair(privateKey: string): Ed25519Keypair {
const { secretKey } = decodeSuiPrivateKey(privateKey);
return Ed25519Keypair.fromSecretKey(secretKey);
}
// Testnet DeepBook client. The SDK ships Testnet package, coin, and pool
// constants, so you reference pools and coins by key (for example 'DEEP_SUI' or
// 'DEEP') instead of hardcoding IDs. Read-only calls work without a manager.
export function deepbookClient(
address: string,
balanceManagers?: { [key: string]: BalanceManager },
): DeepBookTestnetClient {
return new SuiGrpcClient({
network: 'testnet',
baseUrl: 'https://fullnode.testnet.sui.io:443',
}).$extend(deepbook({ address, balanceManagers }));
}
import { Transaction } from '@mysten/sui/transactions';
import type { DeepBookTestnetClient } from './client.js';
// Deposit DEEP into a BalanceManager. DEEP held in the manager pays trading
// fees, and staking it in a pool unlocks the taker-fee discount. `deepAmount` is
// in whole DEEP; the SDK scales it to the coin's 6 decimals.
export function fundManagerWithDeep(
client: DeepBookTestnetClient,
managerKey: string,
deepAmount: number,
): Transaction {
const tx = new Transaction();
tx.add(client.deepbook.balanceManager.depositIntoManager(managerKey, 'DEEP', deepAmount));
return tx;
}
Sign and execute the returned transaction with your keypair. See BalanceManager for creating and sharing a manager.
Obtain Testnet DEEP, USDC, and SUI
There is no Testnet DEEP faucet, by design: the DEEP token's treasury cap is locked in a shared ProtectedTreasury whose only public supply function is burn, and the test coins transfer their treasury caps to the deployer at publish. Nobody can mint DEEP or the test coins. Get DEEP one of two ways:
- Token-request form (reliable): the DeepBook Testnet token request form grants DEEP and quote assets such as DBUSDC directly. Use it as the default, and always for quote assets.
- Swap SUI for DEEP (when the book has liquidity): on the whitelisted
DEEP_SUIpool, faucet SUI converts to DEEP with no BalanceManager. The TestnetDEEP_SUIbook is thin and intermittent, so treat this as a convenience, not a guarantee.
- Prerequisites
- A current CLI, updated with
suiup update: version skew between your CLI and the network produces confusing failures. Confirm the client and server API versions match withsui --version. See Install Sui. - An active environment on a current Testnet RPC: check with
sui client active-envandsui client envs, because a stale or wrong RPC URL reads empty balances and rejects transactions. See Sui environment setup.
Step 1: Get Testnet SUI
Find your address with sui client active-address, then check your balance with sui client gas before requesting anything. Faucets are rate-limited per address and IP, so request only when the balance is actually empty. Request Testnet SUI from a Sui faucet, which lists the browser, Discord, and cURL routes. If the primary faucet rate-limits you, use one of those fallback routes.
Step 2: Get DEEP
Request DEEP, and any quote assets, from the token-request form. This route is reliable and does not depend on book state.
If the DEEP_SUI book has liquidity, you can instead swap faucet SUI for DEEP with no BalanceManager, which avoids a chicken-and-egg where you would need DEEP to buy DEEP. Check the quote first with getQuantityOut: if it returns fewer DEEP than the pool's minimum size (10 DEEP), the book is too thin, so use the form. Set a nonzero minOut so a book that empties reverts instead of returning your SUI unfilled:
import { Transaction } from '@mysten/sui/transactions';
import type { DeepBookTestnetClient } from './client.js';
// Swap SUI for DEEP on the DEEP_SUI Testnet pool. That pool is whitelisted
// (zero fee) and the swap needs no BalanceManager, so it bootstraps DEEP from
// faucet SUI. DEEP is the base and SUI the quote, so a quote-for-base swap
// spends SUI and returns DEEP. Set `minDeepOut` to a nonzero value (for example
// 99% of getQuantityOut's `baseOut`): with `minOut: 0`, a thin or empty book
// silently returns your SUI unfilled instead of reverting.
export function swapSuiForDeep(
client: DeepBookTestnetClient,
suiAmount: number,
minDeepOut: number,
recipient: string,
): Transaction {
const tx = new Transaction();
const [deepOut, suiRemainder, deepFee] = tx.add(
client.deepbook.deepBook.swapExactQuoteForBase({
poolKey: 'DEEP_SUI',
amount: suiAmount,
deepAmount: 0,
minOut: minDeepOut,
}),
);
tx.transferObjects([deepOut, suiRemainder, deepFee], recipient);
return tx;
}
Step 3: Deposit DEEP
Deposit the DEEP into your BalanceManager with the funding step above. You can now place fee-paying orders.
Troubleshooting
InsufficientCoinBalance: the transaction spends more of a coin than you hold after gas. The swap draws SUI from the same balance that pays gas, so size it below your SUI balance minus a gas budget, or fund more SUI. The SDK also reserves a default gas budget when you do not set one, so leave room for it or callsetGasBudgetexplicitly and size the swap around it.version unavailable for consumption: you built a transaction from stale state before a previous one finalized. Wait for finality (the SDK'swaitForTransaction) before building the next transaction. Do not blindly retry a rejected transaction, because it can leave the gas coin equivocation-locked.- Swap succeeds but you receive zero DEEP: the book was empty and
minOutwas 0, so the pool returned your SUI unfilled. Set a nonzerominOutfromgetQuantityOutso an empty book reverts, and check the quote before swapping.