# LLMs.txt Source: https://docs.decibel.trade/agents/llms-txt Machine-readable documentation files for LLMs and AI agents ## What is LLMs.txt? [LLMs.txt](https://llmstxt.org/) is a standard for providing website content in a format optimized for large language models. Instead of parsing HTML, CSS, and JavaScript, LLMs can consume a clean Markdown representation of the documentation -- making it easier for AI agents and coding assistants to understand and work with the Decibel API. These files are automatically generated from the full documentation site. ## Available files Concise index of all documentation pages with short descriptions. Use this as a starting point to discover what's available. Complete documentation content in a single Markdown file. Use this when you need the full context of the Decibel API and platform. ### llms.txt A lightweight index that lists every documentation page with its title and a brief description. Useful for: * Discovering available API endpoints and SDK methods * Understanding the overall structure of the documentation * Deciding which sections to read in full ``` https://docs.decibel.trade/llms.txt ``` ### llms-full.txt The complete documentation rendered as a single Markdown file. Useful for: * Loading full API and SDK reference into an LLM context window * Building RAG (Retrieval-Augmented Generation) pipelines over the docs * Providing comprehensive context to coding assistants ``` https://docs.decibel.trade/llms-full.txt ``` ## Usage with AI tools Most AI coding assistants support loading external context. Here are a few examples: ### Claude Code Use the `/fetch` command to pull the docs into your conversation: ``` /fetch https://docs.decibel.trade/llms-full.txt ``` ### Cursor / Windsurf Add the URL as a doc source in your project settings, or paste it into the chat context. ### Custom agents Fetch the file programmatically and include it in your system prompt or context: ```bash theme={null} curl -s https://docs.decibel.trade/llms-full.txt ``` ## Related * [MCP Server](/agents/mcp/overview) - AI agent integration via Model Context Protocol * [Developer Hub](/developer-hub/overview) - Full developer documentation # Installation Source: https://docs.decibel.trade/agents/mcp/installation Set up the Decibel MCP server with Claude Code, Claude Desktop, or other MCP clients ## Prerequisites The MCP server is bundled with the Decibel CLI. You can run it directly with `npx` (no global install required) or install the CLI first: ```bash theme={null} npm install -g @decibeltrade/cli ``` You'll also need: * A [Node API token](/quickstart/node-api-key) from [Geomi](https://geomi.dev) * An API wallet created at [app.decibel.trade/api](https://app.decibel.trade/api) (for trading operations) ## Setup with Claude Code The fastest way to add the MCP server: ```bash theme={null} claude mcp add --transport stdio \ --env DECIBEL_PRIVATE_KEY=ed25519-priv-0x... \ --env DECIBEL_SUBACCOUNT_ADDRESS=0x... \ --env DECIBEL_NETWORK=testnet \ --env DECIBEL_NODE_API_KEY=aptoslabs_... \ -- decibel npx -y --package @decibeltrade/cli decibel-mcp ``` Replace the environment variable values with your own credentials. You can omit `DECIBEL_PRIVATE_KEY` and `DECIBEL_SUBACCOUNT_ADDRESS` if you've already added a default account with `decibel-cli account add`. ## Setup with JSON config Add the following to your MCP client's configuration file. For Claude Code, this is `~/.claude/settings.json`. For Claude Desktop, this is `claude_desktop_config.json`. ```json theme={null} { "mcpServers": { "decibel": { "type": "stdio", "command": "npx", "args": ["-y", "-p", "@decibeltrade/cli", "decibel-mcp"], "env": { "DECIBEL_NETWORK": "testnet", "DECIBEL_PRIVATE_KEY": "ed25519-priv-0x...", "DECIBEL_SUBACCOUNT_ADDRESS": "0x...", "DECIBEL_NODE_API_KEY": "your-node-api-key" } } } } ``` ## Environment variables The MCP server uses the same environment variables as the CLI: | Variable | Required | Description | | ----------------------------- | -------- | ------------------------------------------------------------------------- | | `DECIBEL_NODE_API_KEY` | Yes | Node API key for authentication | | `DECIBEL_PRIVATE_KEY` | Trading | API wallet private key for signing transactions | | `DECIBEL_SUBACCOUNT_ADDRESS` | Trading | Subaccount address | | `DECIBEL_NETWORK` | No | Network: `mainnet`, `testnet` (default), `local` | | `DECIBEL_GAS_STATION_API_KEY` | No | [Gas Station](/quickstart/gas-station) API key for sponsored transactions | `DECIBEL_PRIVATE_KEY` and `DECIBEL_SUBACCOUNT_ADDRESS` are required for trading tools (placing orders, cancelling, etc.). Market data tools (`get_markets`, `get_price`, `get_orderbook`) only require `DECIBEL_NODE_API_KEY`. ## Authentication The MCP server supports the same authentication methods as the CLI, resolved in this order: 1. Environment variables (`DECIBEL_PRIVATE_KEY` + `DECIBEL_SUBACCOUNT_ADDRESS`) 2. Default account from local storage (`~/.decibel/data.db`) For the MCP server, environment variables are the most common approach since they're set in the MCP client configuration. If you prefer stored accounts, run `decibel-cli account add` first and the server will use the default account automatically. ## Verify the connection After configuring your MCP client, ask the AI agent to run a simple query: ``` What markets are available on Decibel? ``` The agent should invoke the `get_markets` tool and return the list of available trading pairs. # MCP Server Overview Source: https://docs.decibel.trade/agents/mcp/overview Model Context Protocol server for AI agent integration with Decibel DEX ## What is the Decibel MCP server? The Decibel MCP server implements the [Model Context Protocol](https://modelcontextprotocol.io), allowing AI agents like Claude to trade on Decibel DEX programmatically. It exposes 25 tools covering: * **Trading** - Place and cancel orders (limit, market, stop, TWAP), close positions, set TP/SL * **Market data** - Prices, orderbook snapshots, market listings * **Account management** - Balances, positions, orders, and trade history The MCP server requires a [Node API token](/quickstart/node-api-key) and an API wallet for trading operations. Get your API token from [Geomi](https://geomi.dev) and create an API wallet at [app.decibel.trade/api](https://app.decibel.trade/api). The MCP server is bundled with the [Decibel CLI](/cli/overview) (`@decibeltrade/cli`). Installing the CLI gives you both the command-line interface and the MCP server. Set up the MCP server with Claude Code, Claude Desktop, or other MCP clients. Full reference for all 25 tools with parameters and descriptions. The CLI exposes the same functionality for direct terminal use. ## How it works The MCP server runs as a local stdio process. An MCP-compatible client (like Claude Code or Claude Desktop) launches the server and communicates with it over stdin/stdout using the Model Context Protocol. Each MCP tool maps directly to a CLI action. The server validates inputs using Zod schemas, calls the Decibel SDK to execute on-chain transactions or query market data, and returns JSON results. ``` AI Agent <-> MCP Client <-> Decibel MCP Server <-> Decibel SDK <-> Aptos Blockchain ``` ## Available tools The server exposes 25 tools organized into four categories: | Category | Tools | Description | | ---------------- | ----- | --------------------------------------------------------------------------- | | Trading | 5 | Limit, market, stop-limit, stop-market, TWAP | | Order management | 6 | Close, cancel, cancel all, cancel TWAP, TP/SL set & cancel | | Account queries | 9 | Positions, orders, balances, TWAPs, TP/SL, trade/order/funding/TWAP history | | Market data | 3 | Markets list, price, orderbook | | Configuration | 2 | Leverage, margin type | See the [Tool Reference](/agents/mcp/reference) for complete details on each tool. ## Related * [CLI Overview](/cli/overview) - Use the same functionality from the terminal * [TypeScript SDK](/typescript-sdk/overview) - Build custom integrations in TypeScript * [REST API](/api-reference/rest/overview) - Direct HTTP API access * [LLMs.txt](/agents/llms-txt) - Machine-readable documentation for AI agents # Tool Reference Source: https://docs.decibel.trade/agents/mcp/reference Complete reference for all Decibel MCP server tools The Decibel MCP server exposes 25 tools. Each tool accepts a JSON input validated with Zod schemas and returns JSON results. ## Trading tools ### `place_limit_order` Place a limit order on Decibel DEX. Returns order ID and transaction hash on success. | Parameter | Type | Required | Description | | --------------- | ------- | -------- | -------------------------------------- | | `side` | string | Yes | `buy`, `sell`, `long`, or `short` | | `size` | number | Yes | Order size (quantity) | | `symbol` | string | Yes | Market symbol (e.g., `BTC/USD`) | | `price` | number | Yes | Limit price | | `timeInForce` | string | No | `gtc` (default), `post-only`, or `ioc` | | `reduceOnly` | boolean | No | Reduce-only order (default: `false`) | | `clientOrderId` | string | No | Client order ID for tracking | ### `place_market_order` Place a market order. Executes immediately at current price with slippage tolerance. | Parameter | Type | Required | Description | | --------------- | ------- | -------- | ------------------------------------ | | `side` | string | Yes | `buy`, `sell`, `long`, or `short` | | `size` | number | Yes | Order size | | `symbol` | string | Yes | Market symbol | | `slippage` | number | No | Slippage percentage (default: `1`) | | `reduceOnly` | boolean | No | Reduce-only order (default: `false`) | | `clientOrderId` | string | No | Client order ID for tracking | ### `place_stop_limit_order` Place a stop limit order. Triggers when the market reaches the stop price, then posts as a limit order at the specified price. | Parameter | Type | Required | Description | | --------------- | ------- | -------- | ------------------------------------------- | | `side` | string | Yes | `buy`, `sell`, `long`, or `short` | | `size` | number | Yes | Order size | | `symbol` | string | Yes | Market symbol | | `price` | number | Yes | Limit price (execution price after trigger) | | `stopPrice` | number | Yes | Stop trigger price | | `timeInForce` | string | No | `gtc` (default), `post-only`, or `ioc` | | `reduceOnly` | boolean | No | Reduce-only order (default: `false`) | | `clientOrderId` | string | No | Client order ID for tracking | ### `place_stop_market_order` Place a stop market order. Triggers when the market reaches the stop price, then executes immediately with slippage tolerance. | Parameter | Type | Required | Description | | --------------- | ------- | -------- | -------------------------------------------------- | | `side` | string | Yes | `buy`, `sell`, `long`, or `short` | | `size` | number | Yes | Order size | | `symbol` | string | Yes | Market symbol | | `stopPrice` | number | Yes | Stop trigger price | | `slippage` | number | No | Slippage percentage from stop price (default: `1`) | | `reduceOnly` | boolean | No | Reduce-only order (default: `false`) | | `clientOrderId` | string | No | Client order ID for tracking | ### `place_twap_order` Place a TWAP (Time-Weighted Average Price) order. Splits execution across a duration at regular intervals. | Parameter | Type | Required | Description | | --------------- | ------- | -------- | ------------------------------------------------ | | `side` | string | Yes | `buy`, `sell`, `long`, or `short` | | `size` | number | Yes | Total order size | | `symbol` | string | Yes | Market symbol | | `duration` | number | Yes | Total duration in seconds (min: 120, max: 86400) | | `frequency` | number | Yes | Execution frequency in seconds (min: 60) | | `reduceOnly` | boolean | No | Reduce-only order (default: `false`) | | `clientOrderId` | string | No | Client order ID for tracking | *** ## Order management tools ### `close_position` Close an open position. Places a reduce-only market order in the opposite direction. Supports partial closes. | Parameter | Type | Required | Description | | ---------- | ------ | -------- | ------------------------------------------- | | `symbol` | string | Yes | Market symbol | | `slippage` | number | No | Slippage percentage (default: `1`) | | `size` | number | No | Partial close size (omit for full position) | ### `cancel_order` Cancel an open order by order ID. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------- | | `orderId` | string | Yes | Order ID | | `symbol` | string | Yes | Market symbol | ### `cancel_all_orders` Cancel all open orders. Optionally filter by market. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------------ | | `symbol` | string | No | Market symbol to filter (cancels all if omitted) | ### `cancel_twap_order` Cancel an active TWAP order by order ID. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------- | | `orderId` | string | Yes | TWAP order ID | | `symbol` | string | Yes | Market symbol | ### `place_tp_sl` Set take-profit and/or stop-loss for an existing position. Omit size fields to apply to the full position. | Parameter | Type | Required | Description | | ---------------- | ------ | -------- | ----------------------------------------- | | `symbol` | string | Yes | Market symbol | | `tpTriggerPrice` | number | No | Take-profit trigger price | | `tpLimitPrice` | number | No | Take-profit limit price (execution price) | | `tpSize` | number | No | Take-profit size (omit for full position) | | `slTriggerPrice` | number | No | Stop-loss trigger price | | `slLimitPrice` | number | No | Stop-loss limit price (execution price) | | `slSize` | number | No | Stop-loss size (omit for full position) | ### `cancel_tp_sl` Cancel a TP/SL order for a position. | Parameter | Type | Required | Description | | --------- | ------ | -------- | -------------- | | `orderId` | string | Yes | TP/SL order ID | | `symbol` | string | Yes | Market symbol | *** ## Account query tools ### `get_positions` Get all open positions for the account. No parameters required. ### `get_orders` Get all open orders for the account. No parameters required. ### `get_balances` Get account balances including wallet USDC, trading account value, and margin info. No parameters required. ### `get_active_twaps` Get all active TWAP orders for the account. No parameters required. ### `get_trade_history` Get recent trade fill history. | Parameter | Type | Required | Description | | --------- | ------ | -------- | -------------------------------------------------- | | `limit` | number | No | Number of trades to return (default: 20, max: 100) | ### `get_order_history` Get order history for the account (all states including filled, cancelled, etc.). | Parameter | Type | Required | Description | | --------- | ------ | -------- | -------------------------------------------------- | | `limit` | number | No | Number of orders to return (default: 20, max: 200) | ### `get_twap_history` Get TWAP order history (completed and cancelled TWAPs). | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------------------- | | `limit` | number | No | Number of TWAP orders to return (default: 20, max: 200) | ### `get_funding_history` Get funding rate payment history. | Parameter | Type | Required | Description | | --------- | ------ | -------- | --------------------------------------------------- | | `limit` | number | No | Number of records to return (default: 20, max: 200) | ### `get_tp_sl` Get all TP/SL orders for a market position, including position-level and fixed-size TP/SL orders. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------- | | `symbol` | string | Yes | Market symbol | *** ## Market data tools ### `get_markets` List all available markets on Decibel DEX with their configurations. No parameters required. ### `get_price` Get current price, funding rate, and open interest for a market. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------- | | `symbol` | string | Yes | Market symbol | ### `get_orderbook` Get the order book (bids and asks) for a market. | Parameter | Type | Required | Description | | --------- | ------ | -------- | --------------------------------------------- | | `symbol` | string | Yes | Market symbol | | `depth` | number | No | Number of price levels (default: 10, max: 20) | *** ## Configuration tools ### `set_leverage` Set leverage for a market. | Parameter | Type | Required | Description | | ------------ | ------ | -------- | ------------------------------- | | `symbol` | string | Yes | Market symbol | | `leverage` | number | Yes | Leverage value (1-100) | | `marginType` | string | No | `cross` (default) or `isolated` | ### `set_margin_type` Switch margin type for a market between cross and isolated. Preserves current leverage. | Parameter | Type | Required | Description | | ------------ | ------ | -------- | --------------------- | | `symbol` | string | Yes | Market symbol | | `marginType` | string | Yes | `cross` or `isolated` | # Get account overview Source: https://docs.decibel.trade/api-reference/account/get-account-overview /api-reference/openapi.json get /api/v1/account_overviews Retrieve comprehensive perp account information including equity, realized/unrealized PnL, margin utilization, and optional performance metrics. Use `include_performance=true` to get historical return metrics. # Get account positions Source: https://docs.decibel.trade/api-reference/account/get-account-positions /api-reference/openapi.json get /api/v1/account_positions Retrieve all open perp positions for a specific account with optional filtering by one perp market address. Includes position size, entry price, unrealized PnL, liquidation price, and margin details. # Get account's open orders Source: https://docs.decibel.trade/api-reference/account/get-accounts-open-orders /api-reference/openapi.json get /api/v1/open_orders Retrieve all currently open perp and spot orders for a specific account. Each order row carries `asset_type`; use `?asset_type=perp|spot` to filter. Includes limit orders, stop orders, and TP/SL orders attached to positions. Supports pagination. # Get aggregate account volume over a date range Source: https://docs.decibel.trade/api-reference/account/get-aggregate-account-volume-over-a-date-range /api-reference/openapi.json get /api/v1/account_volume Returns the account's total, maker, and taker volume (in whole USD) for the requested inclusive date range. When `start_date` and `end_date` are omitted the range defaults to the past 30 days (today() - 29 .. today(), UTC). Both `start_date` and `end_date` must be supplied together (YYYY-MM-DD format). Volume data has up to 5-minute delay (MV refresh interval). # Get subaccounts Source: https://docs.decibel.trade/api-reference/account/get-subaccounts /api-reference/openapi.json get /api/v1/subaccounts Retrieve all subaccounts for a specific owner address. Returns subaccount addresses and their associated metadata. # Get user fees and fee schedule Source: https://docs.decibel.trade/api-reference/account/get-user-fees-and-fee-schedule /api-reference/openapi.json get /api/v1/user_fee_rates Returns the user's current maker/taker fee rates, fee tier based on the on-chain fee window, the full fee schedule for all VIP tiers, and daily volume history for that same window. Fee rates are decimal numbers where 0.000450 = 0.045%. Volume values are in whole USD. Volume data has up to 5-minute delay (MV refresh interval). The current on-chain fee window includes today plus the previous 30 UTC calendar days. # Get user funding rate history Source: https://docs.decibel.trade/api-reference/account/get-user-funding-rate-history /api-reference/openapi.json get /api/v1/funding_rate_history Retrieve perp funding rate payment history for a specific user. Shows funding payments including the direction, amount, and associated fees. Supports filtering by perp market, side, and timestamp range. Supports sorting and pagination. Page size is capped at 200. # Get user order history Source: https://docs.decibel.trade/api-reference/account/get-user-order-history /api-reference/openapi.json get /api/v1/order_history Retrieve paginated perp and spot order history for a specific user including filled, cancelled, and expired orders. Supports filtering by one concrete market address, order type, status, side, reduce-only, and timestamp range. Supports sorting by timestamp (default: descending). Page size is capped at 200. # Get user trade history Source: https://docs.decibel.trade/api-reference/account/get-user-trade-history /api-reference/openapi.json get /api/v1/trade_history Retrieve perp trade history for a specific user with optional filtering by one perp market address, order ID, side, and timestamp range. Returns executed trades with price, size, PnL, and fee details. Supports sorting by timestamp (default: descending) and pagination. Page size is capped at 200. # GET /api/v1/affiliates/codes/{account} Source: https://docs.decibel.trade/api-reference/affiliates/get-apiv1affiliatescodes /api-reference/openapi.json get /api/v1/affiliates/codes/{account} Returns referral codes owned by an account with per-code usage stats. Affiliate codes (is_affiliate = true) are always returned. Non-affiliate codes are only returned if the account has >= $1,000 all-time trade volume. Maps to the Affiliates dashboard. # GET /api/v1/affiliates/codes/{account}/analytics Source: https://docs.decibel.trade/api-reference/affiliates/get-apiv1affiliatescodes-analytics /api-reference/openapi.json get /api/v1/affiliates/codes/{account}/analytics Internal only: requires the API Gateway `x-aptos-identifier` header to match an allowlisted application ID. Returns 403 otherwise. # GET /api/v1/affiliates/earnings/{account} Returns affiliate earnings breakdown for an account, including per-user referral amps earned at L1 (10%/15%) and L2 (5%) rates. Source: https://docs.decibel.trade/api-reference/affiliates/get-apiv1affiliatesearnings-returns-affiliate-earnings-breakdown-for-an-account-including-per-userreferral-amps-earned-at-l1-10%15%-and-l2-5%-rates /api-reference/openapi.json get /api/v1/affiliates/earnings/{account} # Get daily stats Source: https://docs.decibel.trade/api-reference/analytics/get-daily-stats /api-reference/openapi.json get /api/v1/daily_stats Returns perp daily volume, fees, revenue, and open interest for a given time range. Designed for DefiLlama integration. # Get leaderboard Source: https://docs.decibel.trade/api-reference/analytics/get-leaderboard /api-reference/openapi.json get /api/v1/leaderboard Retrieve the trading leaderboard with rankings based on trading performance metrics. Results are paginated and can be sorted by account value, realized PnL, ROI, or trading volume. Use the `search_term` parameter to filter accounts by address prefix. # Get points leaderboard Source: https://docs.decibel.trade/api-reference/analytics/get-points-leaderboard /api-reference/openapi.json get /api/v1/points_leaderboard Retrieve the Hz/Amps points leaderboard with rankings by total Hz or realized PnL. Results are paginated and can be sorted by total_amps or realized_pnl. Use the `search_term` parameter to filter by owner address prefix. # Get portfolio chart data Source: https://docs.decibel.trade/api-reference/analytics/get-portfolio-chart-data /api-reference/openapi.json get /api/v1/portfolio_chart Returns time series data for PnL or account value over specified time range. PnL = Cumulative Realized PnL from completed trades. Account Value = Initial Deposits - Withdrawals + Realized PnL (excludes unrealized PnL). # Returns the total number of users with points and total amps distributed. Source: https://docs.decibel.trade/api-reference/analytics/returns-the-total-number-of-users-with-points-and-total-amps-distributed /api-reference/openapi.json get /api/v1/points/global # Get bulk order fills Source: https://docs.decibel.trade/api-reference/bulk-orders/get-bulk-order-fills /api-reference/openapi.json get /api/v1/bulk_order_fills Retrieve fills for bulk orders with optional filtering by one concrete market, sequence number, or range. By default returns both perp and spot fills together (each row tagged with `asset_type`); set `?asset_type=perp|spot` to filter. # Get bulk order status Source: https://docs.decibel.trade/api-reference/bulk-orders/get-bulk-order-status /api-reference/openapi.json get /api/v1/bulk_order_status Retrieve the status of a specific bulk order (placed or rejected). Use `?asset_type=spot` to query the spot bulk-order tables; defaults to perp. The `market` parameter is one concrete market address, not a base-asset group. # Get bulk orders Source: https://docs.decibel.trade/api-reference/bulk-orders/get-bulk-orders /api-reference/openapi.json get /api/v1/bulk_orders Retrieve the latest bulk orders for a specific user with optional filtering by one concrete market address. Returns one bulk order per market (perp + spot together by default) with the current bid/ask levels and fills applied. Each row carries an `asset_type` discriminator (`"perp"` or `"spot"`) and the request may optionally filter to a single product via `?asset_type=perp|spot`. # Aggregates sum over all campaigns; `claims` is paged by `limit` / `offset`. Source: https://docs.decibel.trade/api-reference/campaigns/aggregates-sum-over-all-campaigns;-`claims`-is-paged-by-`limit`-`offset` /api-reference/openapi.json get /api/v1/campaigns/account # Get account's campaign locks Source: https://docs.decibel.trade/api-reference/campaigns/get-accounts-campaign-locks /api-reference/openapi.json get /api/v1/campaign_locks Returns the latest state of each FFT campaign lock for the account, sorted by lock time descending. Optionally filtered by campaign and status. # Get account's protected (FFT) trials Source: https://docs.decibel.trade/api-reference/campaigns/get-accounts-protected-fft-trials /api-reference/openapi.json get /api/v1/protected_trials Returns the account's active protected trials plus a paginated terminal history (organic closes and admin resets). `limit`/`offset` apply to `history` only. An optional `campaign_addr` scopes the whole response. # Get apiv1campaignsactive Source: https://docs.decibel.trade/api-reference/campaigns/get-apiv1campaignsactive /api-reference/openapi.json get /api/v1/campaigns/active # Get all available markets Source: https://docs.decibel.trade/api-reference/market-data/get-all-available-markets /api-reference/openapi.json get /api/v1/markets Returns a list of all trading markets (perp + spot) with their configuration details including leverage limits, tick sizes, decimal precision, and current market mode (Open, ReduceOnly, CloseOnly). Each row carries an `asset_type` discriminator (`"perp"` or `"spot"`). # Get asset contexts Source: https://docs.decibel.trade/api-reference/market-data/get-asset-contexts /api-reference/openapi.json get /api/v1/asset_contexts Retrieve perp market contexts including current prices, 24h volume, 24h price change, funding rates, and open interest for all perp markets or one perp market address. # Get candlestick (OHLC) data Source: https://docs.decibel.trade/api-reference/market-data/get-candlestick-ohlc-data /api-reference/openapi.json get /api/v1/candlesticks Retrieve perp candlestick data for one perp market address and time range. Spot candlesticks are available from the `market_candlestick:{marketAddr}:{interval}` WebSocket topic; spot and perp markets with the same base asset have different market addresses and must be requested separately. Supports intervals: 1m, 15m, 1h, 4h, 1d. Missing intervals are interpolated using the last known close price. Maximum 1000 candles per request. Optionally set `filterWicks=true` to suppress extreme H/L wicks caused by liquidation cascades or low-liquidity outlier fills. The filter computes a cross-candle volume-weighted typical price and standard deviation, then clamps each candle's high and low to `[VWAP ± nSigma × σ_v]` without touching open or close. # Get contract specifications Source: https://docs.decibel.trade/api-reference/market-data/get-contract-specifications /api-reference/openapi.json get /api/v1/contract_specs Returns contract specifications for all perpetual contracts, per the CoinGecko/CMC derivatives endpoint spec. # Get contracts summary Source: https://docs.decibel.trade/api-reference/market-data/get-contracts-summary /api-reference/openapi.json get /api/v1/contracts Returns a summary of all perpetual contracts traded on the exchange, # Get DEX registration Source: https://docs.decibel.trade/api-reference/market-data/get-dex-registration /api-reference/openapi.json get /api/v1/dex Retrieve DEX configuration and registration details. # Get market prices Source: https://docs.decibel.trade/api-reference/market-data/get-market-prices /api-reference/openapi.json get /api/v1/prices Retrieve current perp prices for one or all perp markets, including oracle price, mark price, funding rate, and open interest. Use `market=all` or omit the parameter to fetch all perp markets. Spot markets do not publish `/prices` rows; derive spot mid price from `/orderbook` or the `depth:{marketAddr}` WebSocket topic. # Get orderbook depth Source: https://docs.decibel.trade/api-reference/market-data/get-orderbook-depth /api-reference/openapi.json get /api/v1/orderbook Returns bid/ask depth (50 levels each side) for one concrete market address. Supports both perp and spot market addresses; spot and perp markets with the same base asset are different markets with different addresses and are never combined. # Get spot asset contexts Source: https://docs.decibel.trade/api-reference/market-data/get-spot-asset-contexts /api-reference/openapi.json get /api/v1/spot/asset_contexts 24h stats (volume, high/low, last price, prev-day price) plus the live book mid for every registered spot market. The spot counterpart of `/asset_contexts`; perp-only concepts (funding, open interest, mark and oracle prices) are deliberately absent. 24h change = (last_price - prev_day_price) / prev_day_price, derived client-side; `prev_day_price` is null for markets that never traded before the 24h boundary. # Get trades Source: https://docs.decibel.trade/api-reference/market-data/get-trades /api-reference/openapi.json get /api/v1/trades Retrieve recent trades for a specific market ordered by most recent first. Optionally filter by order ID to get trades for a specific order. Supports pagination. Spot markets return one row per fill from the taker's perspective (matching the `market_trades` WS topic); the order ID filter matches either side's order. # Get amps breakdown for an owner Source: https://docs.decibel.trade/api-reference/points/get-amps-breakdown-for-an-owner /api-reference/openapi.json get /api/v1/points/amps Returns total amps with per-category breakdown (trading, streak, referral, vault). All values are sourced from the points leaderboard MV, guaranteeing consistency with the leaderboard rankings. # Get per-day Amps for an owner Source: https://docs.decibel.trade/api-reference/points/get-per-day-amps-for-an-owner /api-reference/openapi.json get /api/v1/points/amps/daily Returns one row per season day, newest first, split into trading / streak / referral / vault. Excludes `bonus_amps` — there is no per-day source for it. # Get S0 predeposit USDC reward for a user Source: https://docs.decibel.trade/api-reference/predeposit-rewards/get-s0-predeposit-usdc-reward-for-a-user /api-reference/openapi.json get /api/v1/predeposits/rewards # Get a referrer's referred clients with lifecycle segments Source: https://docs.decibel.trade/api-reference/referrals/get-a-referrers-referred-clients-with-lifecycle-segments /api-reference/openapi.json get /api/v1/referrals/clients Segment counts across the whole referral set, plus a filtered page of clients ordered by window volume. Carries no commission amounts: the accrual ledger is not built yet. # Get a referrer's sub-affiliates Source: https://docs.decibel.trade/api-reference/referrals/get-a-referrers-sub-affiliates /api-reference/openapi.json get /api/v1/referrals/sub-affiliates Direct referrals who went on to refer others, with their downline size and that downline's window volume. Carries no override amounts: the accrual ledger they would come from does not exist yet. # Get an affiliate's accrued commission Source: https://docs.decibel.trade/api-reference/referrals/get-an-affiliates-accrued-commission /api-reference/openapi.json get /api/v1/referrals/commissions What the affiliate has earned: today, since Monday, and over all time, plus a daily breakdown carrying the tier and any anti-farming penalty that was in force each day. This is not what is claimable. Claimable commission is an on-chain campaign allocation and comes from the campaigns endpoints; this is the off-chain ledger of what is owed. # GET /api/v1/referrals/code/{code} Source: https://docs.decibel.trade/api-reference/referrals/get-apiv1referralscode /api-reference/openapi.json get /api/v1/referrals/code/{code} Pre-wallet-connect validation of a referral code. Returns whether the code exists and is still active (can accept new referrals). No auth needed. If the code doesn't exist, returns `is_valid: false` (not a 404). # Get fee revenue generated by a referrer's network Source: https://docs.decibel.trade/api-reference/referrals/get-fee-revenue-generated-by-a-referrers-network /api-reference/openapi.json get /api/v1/referrals/fees Net fees the referred network paid, the builder kickbacks owed on those same fills, and the difference — the basis an affiliate commission would be computed on. Returns no commission amount: no rate is signed off and no accrual ledger exists. # Get per-code performance for a referrer Source: https://docs.decibel.trade/api-reference/referrals/get-per-code-performance-for-a-referrer /api-reference/openapi.json get /api/v1/referrals/code-performance Redemptions and traded volume per referral code. Not paginated: an affiliate is capped at a handful of codes, so the whole set fits one response. # Get referred volume per day for a referrer Source: https://docs.decibel.trade/api-reference/referrals/get-referred-volume-per-day-for-a-referrer /api-reference/openapi.json get /api/v1/referrals/volume/daily Both-sides USD notional traded by the referrer's network, newest day first. Days with no trading are omitted; clients fill the gaps. # Get the referral funnel for a referrer Source: https://docs.decibel.trade/api-reference/referrals/get-the-referral-funnel-for-a-referrer /api-reference/openapi.json get /api/v1/referrals/funnel Sign-ups and first-time deposits per UTC day, newest day first. Days with no activity are omitted; clients fill the gaps. # Get trading activity of a referrer's referred clients Source: https://docs.decibel.trade/api-reference/referrals/get-trading-activity-of-a-referrers-referred-clients /api-reference/openapi.json get /api/v1/referrals/activity Per-level window totals plus a page of direct (L1) referrals, each carrying the L2 clients it referred. Carries no commission figures: the accrual ledger those would come from does not exist yet. # Handler to get referral info for an account (who referred them) Source: https://docs.decibel.trade/api-reference/referrals/handler-to-get-referral-info-for-an-account-who-referred-them /api-reference/openapi.json get /api/v1/referrals/account/{account} # Handler to get referrer statistics. Non-affiliate referrers must meet the minimum trade volume threshold to see their referral codes. Affiliate referrers always see all codes. Source: https://docs.decibel.trade/api-reference/referrals/handler-to-get-referrer-statisticsnon-affiliate-referrers-must-meet-the-minimum-trade-volume-thresholdto-see-their-referral-codes-affiliate-referrers-always-see-all-codes /api-reference/openapi.json get /api/v1/referrals/stats/{account} # Handler to get users referred by a referrer Source: https://docs.decibel.trade/api-reference/referrals/handler-to-get-users-referred-by-a-referrer /api-reference/openapi.json get /api/v1/referrals/users # POST /api/v1/referrals/redeem Source: https://docs.decibel.trade/api-reference/referrals/post-apiv1referralsredeem /api-reference/openapi.json post /api/v1/referrals/redeem Redeems a referral code for an account. Validates the code in ClickHouse, then submits an `admin_create_new_subaccount` transaction on-chain to create the user's subaccount (bypassing invite-only gating). Referral tracking (code → user → referrer) stays entirely off-chain in ClickHouse. Fee discounts and on-chain referral relationships will be bulk-registered post-TGE. After successful on-chain tx, writes a record to `referral_redemptions` in ClickHouse to track usage_count for code exhaustion. This handler is **idempotent**: retrying the same (account, code) pair returns 200. Retrying with a *different* code returns 409. **Graceful degradation**: if ClickHouse writes fail after on-chain tx success, the handler still returns 200 (the tx is the source of truth). Failed CH writes are logged with `RECONCILE_NEEDED` prefix for manual follow-up. # Authentication Source: https://docs.decibel.trade/api-reference/rest/authentication How to authenticate REST API requests All REST API endpoints require authentication via Bearer token. ### Getting Credentials See the [TypeScript Starter Kit](/quickstart/typescript-starter-kit) for step-by-step instructions on: 1. [Creating an API Wallet](/quickstart/typescript-starter-kit#create-api-wallet), a separate wallet for signing API transactions (not your main login wallet). 2. Getting a Bearer Token from [Geomi](https://geomi.dev/docs/start). ### Using Authentication Include two headers with every authenticated request: Origin (your application's origin URL) and Authorization (Bearer token from Geomi, see above) ```bash theme={null} curl -H "Origin: https://testnet-app.decibel.trade/trade" \ -H "Authorization: Bearer " \ https://api.testnet.aptoslabs.com/decibel/ ``` Replace `` with your Bearer token from Geomi. ## Security Best Practices * Never commit tokens to version control * Use environment variables in your code * Rotate tokens periodically ## Related Step-by-step guide to creating API credentials How to handle authentication errors # Error Handling Source: https://docs.decibel.trade/api-reference/rest/errors Common API errors and how to handle them The REST API uses standard HTTP status codes and returns JSON error objects with detail about what went wrong. ## Error Response Format All error responses have the same shape: ```json theme={null} { "status": "failed", "message": "Human-readable error description" } ``` The `status` field is one of: | Status | Meaning | | ---------- | --------------------------------- | | `failed` | Generic error | | `timeout` | Query execution timed out | | `notFound` | Requested resource does not exist | ### Examples **Bad request (400):** ```json theme={null} { "status": "failed", "message": "Bad Request: missing required parameter 'market'" } ``` **Not found (404):** ```json theme={null} { "status": "notFound", "message": "Market not found" } ``` **Timeout (504):** ```json theme={null} { "status": "timeout", "message": "Query execution timed out. Please try a more specific query or reduce the time range." } ``` **Internal error (500):** ```json theme={null} { "status": "failed", "message": "Service temporarily unavailable. Please try again later." } ``` ## HTTP Status Codes | Status | Meaning | | ------ | --------------------------------------------------------------- | | 200 | Success | | 400 | Bad Request: Invalid parameters | | 401 | Unauthorized: Missing or invalid token | | 403 | Forbidden: Token lacks required scope | | 404 | Not Found: Resource doesn't exist | | 429 | Too Many Requests: Rate limit exceeded | | 500 | Server Error: Something went wrong on our end | | 501 | Not Implemented: Endpoint not enabled on this deployment | | 503 | Service Unavailable: Server temporarily overloaded, retry later | | 504 | Gateway Timeout: Query took too long | ### Best Practices 1. Implement exponential backoff for 500/504 errors 2. Cache responses where appropriate 3. Batch requests when possible 4. Use WebSocket for real-time data instead of polling ## SDK Error Handling See [TypeScript SDK Error Responses](/typescript-sdk/error-responses) for SDK-specific error handling. ## Related How to get and use bearer tokens API basics and available endpoints # REST API Overview Source: https://docs.decibel.trade/api-reference/rest/overview HTTP endpoints for Decibel market, account, history, rewards, and referral data The Decibel REST API provides HTTP endpoints under `/api/v1` for market data, account data, history, analytics, rewards, and referral workflows. ## Authentication Scope Most production traffic is expected to include: * `Authorization: Bearer ` * `Origin: ` See [Authentication](/api-reference/rest/authentication) for credential setup. Implementation note: authentication and access control can be enforced at multiple layers (gateway and service). Treat endpoint-level access policy as deployment-configurable rather than assuming the same behavior in every environment. ## Base URL | Network | Base URL | | ------- | ------------------------------------------- | | Testnet | `https://api.testnet.aptoslabs.com/decibel` | | Mainnet | `https://api.mainnet.aptoslabs.com/decibel` | ## Request Format * Endpoints are rooted at `/api/v1/...` * Current public methods are `GET` and `POST` * Most endpoints use query/path parameters; no generic request body format applies globally ## Spot and Perp Coverage Some endpoints return both perpetual and spot rows. Mixed responses use `asset_type` with values `perp` or `spot`. | Endpoint | Spot behavior | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `/api/v1/markets` | Returns perp and spot markets together; each market carries `asset_type` | | `/api/v1/open_orders` | Returns perp and spot orders by default; filter with `?asset_type=perp` or `?asset_type=spot` | | `/api/v1/order_history` | Returns perp and spot order history by default; filter with `?asset_type=perp` or `?asset_type=spot`; `market` is one concrete market address | | `/api/v1/trade_history` | Returns perp and spot trade history by default; filter with `?asset_type=perp` or `?asset_type=spot`; `market` is one concrete market address | | `/api/v1/orders` | Looks up perp and spot order IDs by default for one concrete market address; `client_order_id` is perp-only | | `/api/v1/bulk_orders` | Returns perp and spot bulk-order state by default; filter with `?asset_type=perp` or `?asset_type=spot`; `market` is one concrete market address | | `/api/v1/bulk_order_fills` | Returns perp and spot bulk-order fills by default; filter with `?asset_type=perp` or `?asset_type=spot`; `market` is one concrete market address | | `/api/v1/bulk_order_status` | Defaults to perp; pass `?asset_type=spot` for spot status; `market` is one concrete market address | | `/api/v1/orderbook` | Accepts one perp or spot market address; the request resolves to exactly one market | | `/api/v1/trades` | Accepts one perp or spot market address; spot rows are returned from the taker's perspective | | `/api/v1/candlesticks` | Accepts one perp or spot market address; spot candles are aggregated from spot trades | | `/api/v1/spot/asset_contexts` | Spot-only 24h stats plus live book mid for registered spot markets | Market-address filters never mean "all BTC products". A spot BTC market and a perp BTC market are different markets with different addresses, so request the product-specific market you want. `/api/v1/prices`, `/api/v1/funding_rate_history`, `/api/v1/asset_contexts`, `/api/v1/daily_stats`, positions, and account-margin endpoints are perp-only. Spot markets do not have oracle price, mark price, funding, open interest, or positions; use `/api/v1/spot/asset_contexts`, `/api/v1/orderbook`, or the `all_spot_mids` / `depth:{marketAddr}` WebSocket topics for spot display prices. ### Spot DTO Notes * Spot `/api/v1/markets` rows use `asset_type="spot"`, `sz_decimals` from the base asset, and `px_decimals` from the quote asset. Perp-only fields such as `max_leverage`, `max_open_interest`, `unrealized_pnl_haircut_bps`, `category`, and `is_isolated_only` use neutral defaults. * Spot `OrderDto` rows use `time_in_force` for `GTC`, `POST_ONLY`, or `IOC`. Spot has no `client_order_id`, reduce-only flag, TP/SL, parent chain, or trigger condition, so those fields are empty, false, or null. * Spot `TradeDto` rows use `action="Buy"` or `"Sell"` from the row account's perspective. Spot has no position PnL or funding, so `realized_pnl_amount` and `realized_funding_amount` are zero. `fee_amount` is the side's actual fee, and `fee_asset` identifies whether that fee is denominated in the base or quote asset. * Spot bulk-order and bulk-order-fill DTOs share the perp response shape, carry `asset_type="spot"`, and normalize prices/sizes with the spot market's quote/base decimals. ### Example Request ```bash theme={null} curl -H "Origin: https://testnet-app.decibel.trade/trade" \ -H "Authorization: Bearer " \ "https://api.testnet.aptoslabs.com/decibel/api/v1/prices" ``` ### Example Response ```json theme={null} [ { "market": "0x...", "oracle_px": 97250.5, "mark_px": 97248.3, "mid_px": 97249.0, "funding_rate_bps": 0.12, "is_funding_positive": true, "transaction_unix_ms": 1718000000000, "open_interest": 5200000.0 } ] ``` ## Available Endpoints The list below is aligned to runtime routes in `rust/trading-api/src/http/routes.rs`. ### Market Data | Endpoint | Description | | --------------------------------- | ----------------------------------------------------------- | | `GET /api/v1/markets` | List available perp and spot markets | | `GET /api/v1/candlesticks` | Perp and spot OHLCV candlestick data for one market address | | `GET /api/v1/prices` | Latest perp prices/funding/open interest | | `GET /api/v1/trades` | Recent trades for one perp or spot market address | | `GET /api/v1/dex` | DEX registration/metadata | | `GET /api/v1/contracts` | Contract metadata | | `GET /api/v1/contract_specs` | Contract spec metadata | | `GET /api/v1/orderbook` | One perp or spot order book snapshot by market address | | `GET /api/v1/spot/asset_contexts` | Spot 24h stats plus live book mid | ### Account and Trading | Endpoint | Description | | ------------------------------- | ---------------------------------------------------------------------------------------- | | `GET /api/v1/account_positions` | Perp account positions | | `GET /api/v1/open_orders` | Open perp and spot orders | | `GET /api/v1/orders` | Order lookup across perp and spot for one market address; `client_order_id` is perp-only | | `GET /api/v1/account_overviews` | Perp account overview and margins | | `GET /api/v1/subaccounts` | Subaccounts | | `GET /api/v1/user_fee_rates` | Current maker/taker rates, fee tier, full fee schedule, and 30-day daily volume history | ### History | Endpoint | Description | | ---------------------------------- | ------------------------------ | | `GET /api/v1/trade_history` | Perp and spot trade history | | `GET /api/v1/order_history` | Perp and spot order history | | `GET /api/v1/funding_rate_history` | Perp funding rate history | | `GET /api/v1/account_fund_history` | Account funding history | | `GET /api/v1/asset_contexts` | Perp asset context snapshots | | `GET /api/v1/withdraw_queue` | Withdrawal queue history/state | ### TWAP and Bulk Orders | Endpoint | Description | | ------------------------------- | --------------------------------------------------------------------------------------- | | `GET /api/v1/active_twaps` | Active TWAP orders | | `GET /api/v1/twap_history` | TWAP order history | | `GET /api/v1/bulk_orders` | Perp and spot bulk-order states; market filter is one concrete market | | `GET /api/v1/bulk_order_fills` | Perp and spot bulk-order fill history; market filter is one concrete market | | `GET /api/v1/bulk_order_status` | Bulk-order status for one concrete market; defaults to perp, supports `asset_type=spot` | ### Vaults | Endpoint | Description | | --------------------------------------- | -------------------------------- | | `GET /api/v1/vaults` | List all vaults | | `GET /api/v1/account_owned_vaults` | Vaults owned by account | | `GET /api/v1/account_vault_performance` | Vault performance for an account | ### Analytics and Points | Endpoint | Description | | ------------------------------------ | -------------------------- | | `GET /api/v1/leaderboard` | Trading leaderboard | | `GET /api/v1/points_leaderboard` | Points leaderboard | | `GET /api/v1/portfolio_chart` | Portfolio chart | | `GET /api/v1/delegations` | Delegation info | | `GET /api/v1/daily_stats` | Perp daily stats | | `GET /api/v1/predeposits/rewards` | Predeposit rewards | | `GET /api/v1/points/trading/account` | Trading points for account | | `GET /api/v1/points/trading/amps` | Trading amps for account | | `GET /api/v1/points/tier` | User tier info | | `GET /api/v1/points/amps` | Owner amps summary | | `GET /api/v1/points/global` | Global points stats | | `GET /api/v1/streaks/account` | Account streak stats | ### Referral and Affiliate | Endpoint | Description | | ------------------------------------------- | -------------------------------- | | `GET /api/v1/referrals/account/{account}` | Referral info by account | | `GET /api/v1/referrals/users` | User referrals | | `GET /api/v1/referrals/stats/{account}` | Referral stats by account | | `GET /api/v1/referrals/code/{code}` | Validate referral code | | `POST /api/v1/referrals/redeem` | Redeem referral code | | `GET /api/v1/affiliates/codes/{account}` | Affiliate codes owned by account | | `GET /api/v1/affiliates/earnings/{account}` | Affiliate earnings by account | ### Backward-Compatible Aliases | Endpoint | Canonical Endpoint | | ------------------------------------ | ----------------------------------- | | `GET /api/v1/user_positions` | `/api/v1/account_positions` | | `GET /api/v1/user_fund_history` | `/api/v1/account_fund_history` | | `GET /api/v1/user_owned_vaults` | `/api/v1/account_owned_vaults` | | `GET /api/v1/user_vault_performance` | `/api/v1/account_vault_performance` | ## SDK Alternative For most application use cases, prefer the TypeScript SDK. See [TypeScript SDK Overview](/typescript-sdk/overview). ## Related Credential setup and auth headers Status codes and error payloads # Get account streak data including qualifying dates and grace days Source: https://docs.decibel.trade/api-reference/streaks/get-account-streak-data-including-qualifying-dates-and-grace-days /api-reference/openapi.json get /api/v1/streaks/account # Get tier info for a user based on percentile-based thresholds Source: https://docs.decibel.trade/api-reference/tier/get-tier-info-for-a-user-based-on-percentile-based-thresholds /api-reference/openapi.json get /api/v1/points/tier # Get aggregated trading Hz for an owner across all their subaccounts Source: https://docs.decibel.trade/api-reference/trading-hz/get-aggregated-trading-hz-for-an-owner-across-all-their-subaccounts /api-reference/openapi.json get /api/v1/points/trading/amps # Get aggregated trading points for an owner across all their active subaccounts Returns total points and per-subaccount breakdown Source: https://docs.decibel.trade/api-reference/trading-points/get-aggregated-trading-points-for-an-owner-across-all-their-active-subaccountsreturns-total-points-and-per-subaccount-breakdown /api-reference/openapi.json get /api/v1/points/trading/account # POST /api/v1/transfers Source: https://docs.decibel.trade/api-reference/transfers/post-apiv1transfers /api-reference/openapi.json post /api/v1/transfers Records a confirmed deposit or withdrawal for attribution analytics. Called by the web client (fire-and-forget) once a transfer confirms. This is an off-chain record — the on-chain UserMovement cannot distinguish a Mesh/CEX deposit, a bridge, and a direct wallet transfer. Generalizes the narrower /mesh/deposit endpoint to all transfer methods and both directions. Keyed on `account` so it joins to on-chain trading volume. Reliable for attribution, NOT for accounting. # Get active TWAP orders Source: https://docs.decibel.trade/api-reference/twap/get-active-twap-orders /api-reference/openapi.json get /api/v1/active_twaps Retrieve currently active TWAP (time-weighted average price) orders for a specific user. Shows orders that have remaining size to be executed. # Get TWAP order history Source: https://docs.decibel.trade/api-reference/twap/get-twap-order-history /api-reference/openapi.json get /api/v1/twap_history Retrieve TWAP order history for a specific user including completed and cancelled orders. Returns historical TWAP orders sorted by most recent first. Supports filtering by timestamp range, sorting by timestamp, and pagination. Page size is capped at 200. # Get apiv1orders Source: https://docs.decibel.trade/api-reference/user/get-apiv1orders /api-reference/openapi.json get /api/v1/orders Get single order details Retrieve details of a specific order by order_id (perp + spot) or client_order_id (perp only). The `market` parameter is one concrete market address; spot and perp markets with the same base asset have different addresses and are not combined. The response is the perp `OrderUpdate` shape; for spot, the inner `order` DTO carries `asset_type: "spot"` and the spot `time_in_force` field is populated. # Get delegations Source: https://docs.decibel.trade/api-reference/user/get-delegations /api-reference/openapi.json get /api/v1/delegations Retrieve active delegations for a specific subaccount. Shows delegated accounts and their associated permissions. # Get user fund history (deposits and withdrawals) Source: https://docs.decibel.trade/api-reference/user/get-user-fund-history-deposits-and-withdrawals /api-reference/openapi.json get /api/v1/account_fund_history Retrieve deposit and withdrawal history for a specific user. Returns chronological list of fund movements with amounts and timestamps. Supports filtering by timestamp range, sorting by timestamp, and pagination. Page size is capped at 200. # Get user fund history (deprecated) Source: https://docs.decibel.trade/api-reference/user/get-user-fund-history-deprecated /api-reference/openapi.json get /api/v1/user_fund_history **Deprecated:** This endpoint is deprecated. Please use `/api/v1/account_fund_history` instead. This endpoint is maintained for backwards compatibility only. # Get user positions (deprecated) Source: https://docs.decibel.trade/api-reference/user/get-user-positions-deprecated /api-reference/openapi.json get /api/v1/user_positions **Deprecated:** This perp-only endpoint is deprecated. Please use `/api/v1/account_positions` instead. This endpoint is maintained for backwards compatibility only. # Get withdrawal queue entries for an account Source: https://docs.decibel.trade/api-reference/user/get-withdrawal-queue-entries-for-an-account /api-reference/openapi.json get /api/v1/withdraw_queue Returns all withdrawal queue entries for the specified account, optionally filtered by status. # Get account-owned vaults Source: https://docs.decibel.trade/api-reference/vaults/get-account-owned-vaults /api-reference/openapi.json get /api/v1/account_owned_vaults Retrieve paginated list of vaults owned by a specific account. Includes vault performance metrics, AUM, and depositor count. # Get account vault performance for all vaults where account has deposits Source: https://docs.decibel.trade/api-reference/vaults/get-account-vault-performance-for-all-vaults-where-account-has-deposits /api-reference/openapi.json get /api/v1/account_vault_performance Retrieve performance metrics for all vaults where the account has deposits, including net deposits, current value, returns, and PnL. Results are ordered by net deposits (descending) and support pagination. # Get public vaults Source: https://docs.decibel.trade/api-reference/vaults/get-public-vaults /api-reference/openapi.json get /api/v1/vaults Retrieve paginated list of public vaults with optional status, vault type, vault address, and search filtering. Use `vault_type` query parameter to filter by 'user' or 'protocol' vaults. Use `vault_address` query parameter to fetch a specific vault by its address (exact match). Use `search` query parameter to filter by vault address, vault name, or manager address (case-insensitive partial match). # Get user-owned vaults (deprecated) Source: https://docs.decibel.trade/api-reference/vaults/get-user-owned-vaults-deprecated /api-reference/openapi.json get /api/v1/user_owned_vaults **Deprecated:** This endpoint is deprecated. Please use `/api/v1/account_owned_vaults` instead. This endpoint is maintained for backwards compatibility only. # Get user vault performance (deprecated) Source: https://docs.decibel.trade/api-reference/vaults/get-user-vault-performance-deprecated /api-reference/openapi.json get /api/v1/user_vault_performance **Deprecated:** This endpoint is deprecated. Please use `/api/v1/account_vault_performance` instead. This endpoint is maintained for backwards compatibility only. # Connection Management Source: https://docs.decibel.trade/api-reference/websocket/connection Connect, authenticate, subscribe, and recover WebSocket sessions This page covers WebSocket connection lifecycle, auth headers, topic subscription format, and reconnection behavior. ## Timeout Maximum session timeout is 1 hour. Clients must reconnect and restore subscriptions. ## Heartbeat The server sends WebSocket ping frames every 30 seconds. The keepalive timer is refreshed when: * A pong frame is received * Any subscribe or unsubscribe activity occurs ## Authentication and Gateway Boundary Use `Sec-WebSocket-Protocol`: ``` Sec-WebSocket-Protocol: decibel, ``` * `decibel` is the accepted subprotocol * `` is your bearer token from [Geomi](https://geomi.dev/docs/start) Implementation note: the WebSocket service itself enforces protocol/topic/message shape and subscription limits. API-key validation is typically enforced at the gateway/proxy layer before traffic reaches the service. See [REST Authentication](/api-reference/rest/authentication) for credential setup. ## Subscribe/Unsubscribe Send JSON with `method` and `topic`: ```json theme={null} {"method":"subscribe","topic":"account_open_orders:0x54011252d627054ccf3401755ef1b068b740f8a1c45886354d1eef549d5907ba"} ``` ### Success Response ```json theme={null} {"success":true,"method":"subscribe","topic":"account_open_orders:0x54011252d627054ccf3401755ef1b068b740f8a1c45886354d1eef549d5907ba"} ``` ### Error Response ```json theme={null} {"success":false,"method":"subscribe","topic":"asd:0x54011252d627054ccf3401755ef1b068b740f8a1c45886354d1eef549d5907ba","error":"Unknown topic type 'asd'"} ``` To unsubscribe, use `"method":"unsubscribe"` with the same topic. ## Handling Reconnection Since the maximum session timeout is 1 hour, your client must handle reconnections gracefully. ### Best Practices 1. Implement exponential backoff for reconnection attempts 2. Track active subscriptions to restore them after reconnecting 3. Use sequence numbers to detect missed messages (for orderbook updates) 4. For `withdraw_queue`, backfill full state from `GET /api/v1/withdraw_queue` and merge WS deltas by `request_id`. ## Error Messages Error responses use the same format as subscribe/unsubscribe responses: ```json theme={null} { "success": false, "method": "subscribe", "topic": "depth:invalid_address", "error": "Invalid market address 'invalid_address' for depth topic" } ``` ### Common Errors | Error | Cause | | ------------------------------------------------------------ | ----------------------------------------------------------------------------- | | `Unknown topic type '{name}'` | Unrecognized channel name | | `Missing user address for {topic} topic` | Topic requires a user/account address but none provided | | `Missing market address for {topic} topic` | Topic requires a market address but none provided | | `Invalid user address '{addr}'` | Malformed address | | `Invalid market address '{addr}'` | Malformed address | | `Invalid aggregation level '{level}' for depth topic` | Must be one of: `1`, `2`, `5`, `10`, `100`, `1000` | | `Invalid interval '{interval}' for market_candlestick topic` | Must be one of: `1m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `1d`, `1w`, `1mo` | | `Maximum client topic subscription count of 150 reached` | Too many active subscriptions on one connection | ## Related Channel catalog and topic names Token and header setup # WebSocket API Overview Source: https://docs.decibel.trade/api-reference/websocket/overview Real-time market and account streams via WebSocket The Decibel WebSocket API provides real-time streaming data for markets, order books, trades, account state, and notifications. Spot and perp use the same topic patterns where the payload shape is shared. Each market-address topic is scoped to one concrete Decibel market. For example, a BTC spot market and a BTC perp market are different markets with different addresses, so they require separate subscriptions. Mixed account-level row payloads carry `asset_type` with values `perp` or `spot`. ## Payload Semantics * `depth` and `market_candlestick` payloads do not include `asset_type`; the subscribed market address identifies whether the payload is for a perp or spot market. * `account_open_orders` and `order_updates` use `OrderDto`. Spot order rows use `time_in_force` and leave perp-only fields such as `client_order_id`, reduce-only, TP/SL, parent, and trigger condition empty, false, or null. * `trades` and `user_trades` use `TradeDto` with `asset_type`. Spot rows use `action` values `Buy` or `Sell`, leave `client_order_id` empty, set `realized_pnl_amount` and `realized_funding_amount` to `0`, and include `fee_asset` when `fee_amount` is denominated in the base or quote asset. * `bulk_orders` and `bulk_order_fills` share the perp DTO shape, carry `asset_type`, and normalize spot prices/sizes with the spot market's quote/base decimals. ## Server URL | Network | URL | | ------- | -------------------------------------------- | | Testnet | `wss://api.testnet.aptoslabs.com/decibel/ws` | | Mainnet | `wss://api.mainnet.aptoslabs.com/decibel/ws` | ## Available Channels ### Market Data | Channel | Description | | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | `depth:{marketAddr}` | Orderbook depth updates for one perp or spot market address | | `depth:{marketAddr}:{level}` | Depth updates for one perp or spot market address with aggregation level `1`, `2`, `5`, `10`, `100`, `1000` (default `1`) | | `trades:{marketAddr}` | Trade stream for one perp or spot market address; rows carry `asset_type` | | `market_price:{marketAddr}` | Perp-only price/funding/open-interest stream | | `all_market_prices` | Perp-only price updates for all markets | | `all_spot_mids` | Spot-only full-market snapshot of book mid and last trade price for every registered spot market | | `market_candlestick:{marketAddr}:{interval}` | OHLCV candlestick data for one perp or spot market address (`1m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `1d`, `1w`, `1mo`) | ### Account | Channel | Description | | -------------------------------------- | -------------------------------------------------------------------------- | | `account_open_orders:{accountAddr}` | Open perp and spot orders for an account; rows carry `asset_type` | | `order_updates:{accountAddr}` | Perp and spot order status/update events; nested orders carry `asset_type` | | `account_positions:{accountAddr}` | Perp positions for an account | | `account_overview:{accountAddr}` | Perp account overview and margin updates | | `user_trades:{accountAddr}` | Perp and spot user trade fills; rows carry `asset_type` | | `notifications:{accountAddr}` | User notifications | | `withdraw_queue:{accountAddr}` | Incremental withdrawal queue updates | | `protected_trial_update:{accountAddr}` | First Trade On Us (protected trial) status updates | ### Bulk Orders | Channel | Description | | -------------------------------- | ---------------------------------------------------------------------------------- | | `bulk_orders:{accountAddr}` | Perp and spot bulk-order status updates, including placed and rejected submissions | | `bulk_order_fills:{accountAddr}` | Perp and spot bulk-order fill events; rows carry `asset_type` | ### TWAP | Channel | Description | | --------------------------------- | ----------------------------- | | `user_active_twaps:{accountAddr}` | Active TWAP orders for a user | ## Topic Compatibility Notes The server still accepts legacy topic names for backward compatibility: * `user_open_orders:{accountAddr}` (legacy) -> canonical `account_open_orders:{accountAddr}` * `user_positions:{accountAddr}` (legacy) -> canonical `account_positions:{accountAddr}` Spot markets do not publish `market_price` or `all_market_prices` rows because they do not have oracle price, mark price, funding, or open interest. Use `all_spot_mids` for a full-market spot display-price snapshot, or `depth:{marketAddr}` and its `best_bid` / `best_ask` fields for one market's live book mid. ## Message Format See [Connection Management](/api-reference/websocket/connection#subscribe-unsubscribe) for subscribe/unsubscribe payloads, auth headers, and error responses. ## Next Steps Connect, authenticate, subscribe, reconnect Managed WebSocket connections via SDK # Account open orders Source: https://docs.decibel.trade/api-reference/websockets/accountopenorders Account's currently open perp and spot orders. Each order row carries `asset_type` (`perp` or `spot`) so clients can demux mixed snapshots. Spot order rows use `time_in_force`, report `order_direction` as `Buy` or `Sell` (spot has no position to open or close, so perp's `Open Long` / `Close Short` vocabulary does not apply), and leave perp-only fields such as `client_order_id`, reduce-only, and TP/SL empty, false, or null. # Account overview Source: https://docs.decibel.trade/api-reference/websockets/accountoverview User's perp account overview including equity, margin, and PnL # Account positions Source: https://docs.decibel.trade/api-reference/websockets/accountpositions Perp-only account positions with PnL and liquidation prices. Spot markets do not have positions. # All market prices Source: https://docs.decibel.trade/api-reference/websockets/allmarketprices Perp-only price updates for all markets. Spot markets do not publish price rows; derive spot mid price from `depth`. # All spot mids Source: https://docs.decibel.trade/api-reference/websockets/allspotmids Live mid + last trade price for every spot market (global topic). Display numbers only: spot has no oracle, and perp prices stay on all_market_prices. # Bulk order fills Source: https://docs.decibel.trade/api-reference/websockets/bulkorderfills User's perp and spot bulk-order fill events. Each fill row carries `asset_type`; spot rows use the same DTO shape with prices and sizes normalized by the spot market's quote/base decimals. # Bulk orders Source: https://docs.decibel.trade/api-reference/websockets/bulkorders User's perp and spot bulk-order status updates, including placed and rejected submissions. The nested bulk order carries `asset_type`; spot rows use the same DTO shape with prices and sizes normalized by the spot market's quote/base decimals. # Market candlestick Source: https://docs.decibel.trade/api-reference/websockets/marketcandlestick Real-time candlestick/OHLCV data for one Decibel market address and interval. The same topic pattern supports perp and spot markets, but spot BTC and perp BTC are different markets with different addresses and require separate subscriptions. Candlestick items do not carry `asset_type`; the subscribed market address identifies the product. # Market depth Source: https://docs.decibel.trade/api-reference/websockets/marketdepth Order book depth for one Decibel market address, perp or spot, with aggregated price levels. Spot BTC and perp BTC are different markets with different addresses and require separate subscriptions. The depth payload does not carry `asset_type`; the subscribed market address identifies the product. Optional aggregationLevel parameter (1, 2, 5, 10, 100, or 1000) can be appended to the topic and defaults to 1. Spot clients derive mid price from `best_bid` and `best_ask` because spot markets do not publish `market_price`. # Market price Source: https://docs.decibel.trade/api-reference/websockets/marketprice Perp-only real-time price updates for a specific market (oracle, mark, mid prices, funding, open interest). Spot markets do not publish this topic; derive spot mid price from `depth`. # Market trades Source: https://docs.decibel.trade/api-reference/websockets/markettrades Real-time trade updates for one Decibel market address, perp or spot (not cached, updates only). Spot BTC and perp BTC are different markets with different addresses and require separate subscriptions. Each trade row carries `asset_type`. Spot rows use `action` values `Buy` or `Sell`, leave `client_order_id` empty, and zero `realized_pnl_amount`, `realized_funding_amount`, and `fee_amount` because spot has no positions/funding and per-side fee attribution is unavailable. # Notifications Source: https://docs.decibel.trade/api-reference/websockets/notifications Real-time notifications for the user, covering perp and spot orders. The nested order carries `asset_type`; spot rows report `order_direction` as `Buy` or `Sell` (spot has no position to open or close, so perp's `Open Long` / `Close Short` vocabulary does not apply). # Order update Source: https://docs.decibel.trade/api-reference/websockets/orderupdate Perp and spot order update for a specific user. The nested order carries `asset_type`. Spot order rows use `time_in_force`, report `order_direction` as `Buy` or `Sell` (spot has no position to open or close, so perp's `Open Long` / `Close Short` vocabulary does not apply), and leave perp-only fields such as `client_order_id`, reduce-only, and TP/SL empty, false, or null. # Protected_trial_update Source: https://docs.decibel.trade/api-reference/websockets/protected_trial_update Real-time protected trial updates for the user. Each push replaces the active set (absence = removal); terminal DTOs are advisory. Degraded reset DTOs omit open-sourced fields like market and opened_at_ms. # User active twaps Source: https://docs.decibel.trade/api-reference/websockets/useractivetwaps User's active TWAP (Time-Weighted Average Price) orders # User trades Source: https://docs.decibel.trade/api-reference/websockets/usertrades User's perp and spot trade fills. Each trade row carries `asset_type`. Spot rows use `action` values `Buy` or `Sell`, leave `client_order_id` empty, and zero `realized_pnl_amount`, `realized_funding_amount`, and `fee_amount` because spot has no positions/funding and per-side fee attribution is unavailable. # Withdraw_queue Source: https://docs.decibel.trade/api-reference/websockets/withdraw_queue Real-time withdrawal queue updates for the user # Configuration Source: https://docs.decibel.trade/cli/configuration Configure accounts, networks, and environment variables for the Decibel CLI ## Authentication The CLI uses **API wallets** for signing transactions on behalf of your Decibel subaccount. API wallets can be created at [app.decibel.trade/api](https://app.decibel.trade/api). They allow programmatic trading without permitting deposits or withdrawals. The CLI resolves credentials in this order: 1. `--account ` flag - Use a named account from local storage 2. `DECIBEL_PRIVATE_KEY` environment variable - API wallet private key 3. `DECIBEL_SUBACCOUNT_ADDRESS` environment variable - Subaccount address (read-only operations) 4. Default account from local storage (`~/.decibel/data.db`) ## Adding an account Run the interactive setup: ```bash theme={null} decibel-cli account add ``` You'll be prompted for: * **Subaccount address** - Your Decibel subaccount address (starts with `0x`) * **Account type** - `api-wallet` (for trading) or `read-only` (for monitoring) * **Private key** - API wallet private key (for `api-wallet` type only) * **Alias** - A short name like `main`, `trading`, or `bot` * **Set as default** - Whether to use this account by default Accounts are stored locally in `~/.decibel/data.db` with private keys encrypted at rest. ### Managing accounts ```bash theme={null} decibel-cli account ls # List all accounts decibel-cli account set-default # Change the default account decibel-cli account remove # Remove an account decibel-cli account info # Show balances and equity ``` ## Network selection The CLI supports four networks: | Network | Description | | --------- | ----------------------- | | `mainnet` | Production (real funds) | | `testnet` | Public testnet | | `local` | Local development | Set the network with the `--network` flag or `DECIBEL_NETWORK` environment variable: ```bash theme={null} # Per-command decibel-cli markets ls --network testnet # Or set globally export DECIBEL_NETWORK=testnet ``` The default network is `testnet`. ## Environment variables | Variable | Description | | ----------------------------- | ------------------------------------------------------------------------- | | `DECIBEL_PRIVATE_KEY` | API wallet private key for signing transactions | | `DECIBEL_SUBACCOUNT_ADDRESS` | Subaccount address for read operations | | `DECIBEL_ACCOUNT_ALIAS` | Account alias from stored accounts | | `DECIBEL_NETWORK` | Network (`mainnet`, `testnet`, `local`) | | `DECIBEL_NODE_API_KEY` | Required. Node API key for authentication | | `DECIBEL_GAS_STATION_API_KEY` | [Gas Station](/quickstart/gas-station) API key for sponsored transactions | You can place these in a `.env` file in your working directory - the CLI loads it automatically via `dotenv`. ## Global options These options are available on all commands: | Option | Description | | ------------------- | ---------------------------------------- | | `--json` | Output in JSON format (machine-readable) | | `--network ` | Network to use | | `--account ` | Use a specific stored account | | `-h, --help` | Show help for any command | ## MCP server The CLI includes a built-in MCP server for AI agent integration. See the [MCP Server Installation](/agents/mcp/installation) page for setup instructions. # Installation Source: https://docs.decibel.trade/cli/installation Install the Decibel CLI globally ## Install the CLI ```bash npm theme={null} npm install -g @decibeltrade/cli ``` ```bash yarn theme={null} yarn global add @decibeltrade/cli ``` ```bash pnpm theme={null} pnpm add -g @decibeltrade/cli ``` Requires Node.js 22 or later. ## Run without installing You can also run the CLI directly with `npx` without a global install: ```bash theme={null} npx -y @decibeltrade/cli markets ls ``` ## Verify installation ```bash theme={null} decibel-cli --version decibel-cli --help ``` You should see the version number and a list of available commands: ``` Usage: decibel-cli [options] [command] Command-line interface for trading on Decibel DEX Options: -V, --version output the version number --network Network to use (mainnet, testnet, local) -h, --help display help for command Commands: account Manage trading accounts markets View market information trade Trading commands help [command] display help for command ``` ## Next steps Set up your accounts and environment variables in [Configuration](/cli/configuration). # CLI Overview Source: https://docs.decibel.trade/cli/overview Decibel CLI for trading, account management, and market data from the terminal ## What is the Decibel CLI? The Decibel CLI (`@decibeltrade/cli`) is a command-line interface for trading on Decibel DEX. It provides direct terminal access to: * **Trading** - Place and cancel orders (limit, market, stop, TWAP), manage positions, set TP/SL * **Account management** - Multi-account support with encrypted local storage * **Market data** - Prices, orderbooks, and real-time WebSocket streaming The CLI requires a [Node API token](/quickstart/node-api-key) for authentication. Get yours from [Geomi](https://geomi.dev) before starting. The CLI also ships with a built-in [MCP server](/agents/mcp/overview) with 25 tools, enabling AI agents like Claude to trade through natural language. Install the CLI globally via npm, yarn, or pnpm. Set up accounts, environment variables, and network selection. Full reference for all available commands and options. ## Quick start ```bash theme={null} # Set required environment variables export DECIBEL_NODE_API_KEY=aptoslabs_... export DECIBEL_NETWORK=testnet # Add your trading account decibel-cli account add # List available markets decibel-cli markets ls # Check BTC price decibel-cli markets price BTC/USD # Place a limit order decibel-cli trade order limit buy 0.01 BTC/USD 50000 # View open positions decibel-cli trade positions ``` ## Design The CLI is designed for two audiences: * **AI agents** (primary) - All commands support `--json` output for machine-readable responses. The built-in MCP server exposes 25 tools for direct agent integration. * **Human power users** (secondary) - Formatted tables, color-coded output, and real-time watch mode via WebSocket. ## MCP server The CLI includes a built-in Model Context Protocol (MCP) server that allows AI agents like Claude to interact with Decibel programmatically. See the [MCP Server](/agents/mcp/overview) section under the Agents tab for setup instructions and the full tool reference. ## Related * [MCP Server](/agents/mcp/overview) - AI agent integration via Model Context Protocol * [TypeScript SDK](/typescript-sdk/overview) - Programmatic SDK for Node.js and browser environments * [REST API](/api-reference/rest/overview) - Direct HTTP API access * [WebSocket API](/api-reference/websocket/overview) - Real-time streaming API # Command Reference Source: https://docs.decibel.trade/cli/reference Complete reference for all Decibel CLI commands ## Account commands Manage locally stored trading accounts. ### `account add` Interactively add a new trading account. ```bash theme={null} decibel-cli account add ``` Prompts for subaccount address, account type (`api-wallet` or `read-only`), private key, alias, and default status. Private keys are encrypted at rest in `~/.decibel/data.db`. ### `account ls` List all stored accounts. ```bash theme={null} decibel-cli account ls [--json] ``` ### `account set-default` Set the default account used when no `--account` flag is provided. ```bash theme={null} decibel-cli account set-default [alias] ``` If `alias` is omitted, an interactive picker is shown. ### `account remove` Remove a stored account. ```bash theme={null} decibel-cli account remove [alias] [-y] ``` | Option | Description | | ------ | ----------------- | | `-y` | Skip confirmation | ### `account info` Show account balances and equity. ```bash theme={null} decibel-cli account info [--json] [--account ] [--network ] ``` Displays: subaccount address, account value, unrealized PnL, withdrawable balance, total margin, and maintenance margin. *** ## Market commands Query market data and prices. ### `markets ls` List all available markets. ```bash theme={null} decibel-cli markets ls [--json] [--network ] ``` Displays: market name, max leverage, tick size, min size, and trading mode. ### `markets price` Get the current price for a market. ```bash theme={null} decibel-cli markets price [--json] [--network ] [-w] ``` | Argument | Description | | -------- | ------------------------------- | | `symbol` | Market symbol (e.g., `BTC/USD`) | | Option | Description | | ------ | -------------------------------------- | | `-w` | Watch price in real-time via WebSocket | Displays: mark price, oracle price, funding rate, and open interest. ### `markets book` View the order book for a market. ```bash theme={null} decibel-cli markets book [--json] [--network ] [-w] [--depth ] ``` | Option | Default | Description | | ------------- | ------- | ------------------------------ | | `-w` | | Watch orderbook in real-time | | `--depth ` | `10` | Number of price levels to show | Displays: color-coded bid/ask levels with size and depth bars. *** ## Trade commands Place orders, manage positions, and view trading history. ### Place orders #### `trade order limit` Place a limit order. ```bash theme={null} decibel-cli trade order limit [options] ``` | Argument | Description | | -------- | --------------------------------- | | `side` | `buy`, `sell`, `long`, or `short` | | `size` | Order size (e.g., `0.01`) | | `symbol` | Market symbol (e.g., `BTC/USD`) | | `price` | Limit price | | Option | Default | Description | | ------------------ | ------- | ---------------------------------------- | | `--tif ` | `gtc` | Time in force: `gtc`, `post-only`, `ioc` | | `--reduce-only` | `false` | Reduce-only order | | `--client-id ` | | Client order ID for tracking | ```bash theme={null} # Buy 0.01 BTC at $50,000 limit decibel-cli trade order limit buy 0.01 BTC/USD 50000 # Post-only sell order decibel-cli trade order limit sell 0.5 ETH/USD 4000 --tif post-only ``` #### `trade order market` Place a market order. ```bash theme={null} decibel-cli trade order market [options] ``` | Argument | Description | | -------- | --------------------------------- | | `side` | `buy`, `sell`, `long`, or `short` | | `size` | Order size | | `symbol` | Market symbol | | Option | Default | Description | | ------------------ | ------- | ---------------------------- | | `--slippage ` | `1` | Max slippage percentage | | `--reduce-only` | `false` | Reduce-only order | | `--client-id ` | | Client order ID for tracking | ```bash theme={null} decibel-cli trade order market buy 0.01 BTC/USD decibel-cli trade order market sell 1 ETH/USD --slippage 0.5 ``` #### `trade order stop-limit` Place a stop limit order. Triggers at the stop price and executes at the limit price. ```bash theme={null} decibel-cli trade order stop-limit [options] ``` | Argument | Description | | ----------- | --------------------------------- | | `side` | `buy`, `sell`, `long`, or `short` | | `size` | Order size | | `symbol` | Market symbol | | `price` | Limit price (execution price) | | `stopPrice` | Trigger price | | Option | Default | Description | | ------------------ | ------- | ---------------------------------------- | | `--tif ` | `gtc` | Time in force: `gtc`, `post-only`, `ioc` | | `--reduce-only` | `false` | Reduce-only order | | `--client-id ` | | Client order ID for tracking | ```bash theme={null} decibel-cli trade order stop-limit sell 0.01 BTC/USD 49000 49500 ``` #### `trade order stop-market` Place a stop market order. Triggers at the stop price and executes immediately. ```bash theme={null} decibel-cli trade order stop-market [options] ``` | Argument | Description | | ----------- | --------------------------------- | | `side` | `buy`, `sell`, `long`, or `short` | | `size` | Order size | | `symbol` | Market symbol | | `stopPrice` | Trigger price | | Option | Default | Description | | ------------------ | ------- | ----------------------------------- | | `--slippage ` | `1` | Slippage percentage from stop price | | `--reduce-only` | `false` | Reduce-only order | | `--client-id ` | | Client order ID for tracking | ```bash theme={null} decibel-cli trade order stop-market sell 0.01 BTC/USD 49000 ``` #### `trade order twap` Place a TWAP (Time-Weighted Average Price) order. Splits the order into smaller sub-orders over a duration. ```bash theme={null} decibel-cli trade order twap --duration --frequency [options] ``` | Argument | Description | | -------- | --------------------------------- | | `side` | `buy`, `sell`, `long`, or `short` | | `size` | Total order size | | `symbol` | Market symbol | | Option | Default | Description | | ----------------------- | ------- | -------------------------------------- | | `--duration ` | | Total execution duration in seconds | | `--frequency ` | | Interval between sub-orders in seconds | | `--reduce-only` | `false` | Reduce-only order | ```bash theme={null} # Buy 1 BTC over 10 minutes, placing sub-orders every 30 seconds decibel-cli trade order twap buy 1 BTC/USD --duration 600 --frequency 30 ``` ### Cancel orders #### `trade cancel` Cancel a specific open order. ```bash theme={null} decibel-cli trade cancel --market [options] ``` | Argument | Description | | --------- | ---------------------- | | `orderId` | The order ID to cancel | | Option | Description | | ------------------- | ------------- | | `--market ` | Market symbol | #### `trade cancel-all` Cancel all open orders. ```bash theme={null} decibel-cli trade cancel-all [--market ] [options] ``` | Option | Description | | ------------------- | --------------------------------- | | `--market ` | Cancel only orders in this market | | `-y, --yes` | Skip confirmation prompt | #### `trade cancel-twap` Cancel an active TWAP order. ```bash theme={null} decibel-cli trade cancel-twap --market [options] ``` ### Close positions #### `trade close` Close an open position at market price. ```bash theme={null} decibel-cli trade close [options] ``` | Argument | Description | | -------- | ------------------------------- | | `symbol` | Market symbol (e.g., `BTC/USD`) | | Option | Default | Description | | ------------------ | ------------- | ---------------------------------------- | | `--slippage ` | `1` | Max slippage percentage | | `--size ` | Full position | Partial close size (omit for full close) | ### TP/SL (Take-Profit / Stop-Loss) #### `trade tp-sl set` Set take-profit and/or stop-loss for a position. ```bash theme={null} decibel-cli trade tp-sl set [options] ``` | Argument | Description | | -------- | ------------- | | `symbol` | Market symbol | | Option | Description | | ---------------------- | ----------------------------------------- | | `--tp-trigger ` | Take-profit trigger price | | `--sl-trigger ` | Stop-loss trigger price | | `--tp-limit ` | Take-profit limit price | | `--sl-limit ` | Stop-loss limit price | | `--tp-size ` | Take-profit size (omit for full position) | | `--sl-size ` | Stop-loss size (omit for full position) | ```bash theme={null} decibel-cli trade tp-sl set BTC/USD --tp-trigger 55000 --sl-trigger 45000 ``` #### `trade tp-sl ls` List active TP/SL orders for a position. ```bash theme={null} decibel-cli trade tp-sl ls [--json] ``` #### `trade tp-sl cancel` Cancel a TP/SL order. ```bash theme={null} decibel-cli trade tp-sl cancel --market ``` ### Configuration #### `trade set-leverage` Set leverage for a market. ```bash theme={null} decibel-cli trade set-leverage ``` | Argument | Description | | ---------- | -------------------------------- | | `symbol` | Market symbol | | `leverage` | Leverage multiplier (e.g., `10`) | | Option | Default | Description | | ------------ | ------- | ------------------- | | `--cross` | `true` | Use cross margin | | `--isolated` | | Use isolated margin | ```bash theme={null} decibel-cli trade set-leverage BTC/USD 10 ``` #### `trade set-margin` Set the margin type for a market. ```bash theme={null} decibel-cli trade set-margin ``` | Argument | Description | | -------- | --------------------- | | `symbol` | Market symbol | | `type` | `cross` or `isolated` | ```bash theme={null} decibel-cli trade set-margin BTC/USD cross ``` ### View trading data #### `trade positions` List open positions. ```bash theme={null} decibel-cli trade positions [--json] [-w] ``` | Option | Description | | ------ | ------------------------------------------ | | `-w` | Watch positions in real-time via WebSocket | #### `trade orders` List open orders. ```bash theme={null} decibel-cli trade orders [--json] [-w] ``` | Option | Description | | ------ | --------------------------------------- | | `-w` | Watch orders in real-time via WebSocket | #### `trade active-twaps` List active TWAP orders. ```bash theme={null} decibel-cli trade active-twaps [--json] ``` #### `trade history` View trade fill history. ```bash theme={null} decibel-cli trade history [--json] [--limit ] ``` #### `trade order-history` View order history (all states: filled, cancelled, etc.). ```bash theme={null} decibel-cli trade order-history [--json] [--limit ] ``` #### `trade twap-history` View TWAP order history. ```bash theme={null} decibel-cli trade twap-history [--json] [--limit ] ``` #### `trade funding-history` View funding rate payment history. ```bash theme={null} decibel-cli trade funding-history [--json] [--limit ] ``` The CLI also includes a built-in MCP server for AI agent integration. See the [MCP Server Tool Reference](/agents/mcp/reference) for the full list of MCP tools. # Bulk Orders Source: https://docs.decibel.trade/developer-hub/guides/bulk-orders Efficient order management for market makers Bulk orders let market makers update their quotes atomically without cancel transactions. Instead of canceling existing orders and placing new ones, you send your desired order state and the system overwrites the previous orders in a single transaction. ## Why Bulk Orders? On other decentralized exchanges, updating quotes requires canceling orders, waiting for confirmation, then placing replacements. This is slow, expensive, and leaves you exposed during the cancel-replace cycle. With Decibel bulk orders, you send your new desired state and previous orders are atomically replaced. One transaction. No cancel step. No exposure window. ## How It Works Bulk orders are stateful updates for a specific market. Each bulk order call overwrites your previous bulk orders in that market. See [Place Bulk Order](/developer-hub/on-chain/order-management/place-bulk-order) for transaction details. ## Limits | Parameter | Limit | | ----------------------------------------- | ----------------- | | Max orders per side per bulk call | 30 | | Active bulk orders per market per account | 1 | | Order types supported | Limit orders only | ## Mixing Bulk and Regular Orders Bulk orders and regular orders are tracked separately. A bulk order update only affects bulk orders, not your regular orders placed via `placeOrder`. ## Canceling All Bulk Orders To remove all bulk orders in a market, submit an empty array. See [Cancel Bulk Order](/developer-hub/on-chain/order-management/cancel-bulk-order) for details. ## Related On-chain reference for bulk orders On-chain reference for canceling bulk orders # Vault Integration Guide Source: https://docs.decibel.trade/developer-hub/guides/vaults Create and manage onchain vaults that pool capital under a single manager with interval-based performance fees and fungible share tokens. Vaults are onchain smart contracts that let you run a trading strategy with pooled capital. Contributors deposit USDC and receive fungible share tokens representing their claim on vault assets. You trade with the pooled funds and earn performance fees on profitable intervals. For how vaults work from a contributor's perspective, see [Vaults](/for-traders/vaults). For the protocol-owned liquidity vault, see [DLP Vault](/for-traders/dlp-vault). This guide walks you through creating a vault on testnet, funding it with USDC, and activating it for contributions. It then covers how vaults work under the hood (lifecycle, fees, shares) and advanced operations like contributing to existing vaults, redeeming shares, and delegating trading permissions. **TypeScript** examples use the [Decibel TypeScript SDK](/typescript-sdk/write-sdk) (`DecibelWriteDex` / `DecibelReadDex`). **Python** examples still use `aptos-sdk` with on-chain entry functions and will be updated in a follow-up. **Testnet funding (Aptos testnet)** — To run the full Part 1 flow (create, contribute, redeem), keep about **210 USDC** in your primary Trading Account (subaccount), in chain units (6 decimals): | Item | Chain units | USDC | | --------------------------------------------- | ------------- | ----------- | | Vault creation fee (deducted from subaccount) | `100_000_000` | \$100 | | `initialFunding` (min activation) | `100_000_000` | \$100 | | Optional `depositToVault` (min contribution) | `10_000_000` | \$10 | | **Suggested subaccount total** | `210_000_000` | **\~\$210** | The creation fee and `initialFunding` are **separate** debits from subaccount collateral. Reference implementation: [`typescript/packages/e2e/src/vault-e2e.ts`](https://github.com/aptos-labs/etna/blob/main/typescript/packages/e2e/src/vault-e2e.ts). Run `cd typescript/packages/e2e && pnpm start:vault-e2e` (see `.env.example` for `PRIVATE_KEY` and `API_KEY`; `NEXT_PUBLIC_GAS_STATION_API_KEY` is only required for that smoke script, not for a typical integration). Fund your account, create a vault on testnet, and activate it. Lifecycle, fees, shares, and parameters. Contributing, redeeming, querying, and delegation. ## Part 1: Launch Your First Vault You can also create and manage vaults through the [Decibel UI](https://app.decibel.trade/accounts) without writing any code. Navigate to Accounts, then click the Vaults tab and "Create Vault." This guide covers the programmatic approach. ### 1. Prerequisites * [Node.js](https://nodejs.org/) 18+ (TypeScript), or Python 3.8+ (Python examples) * An API Wallet with its private key (create one at [app.decibel.trade/api](https://app.decibel.trade/api)) * An API Key (Bearer Token) from [Geomi](https://geomi.dev) (see [Get API Keys](/quickstart/node-api-key)) * Testnet APT for gas fees: paste your API Wallet address into the [Aptos Testnet Faucet](https://aptos.dev/network/faucet). This is your wallet address, not your Trading Account (subaccount) address. **Gas (choose one)** — **Default:** pay gas with testnet APT from the faucet above. **Optional:** set `gasStationApiKey` on `DecibelConfig` to sponsor gas via [Geomi Gas Station](/quickstart/gas-station) (see [SDK configuration](/typescript-sdk/configuration)). Vault integrations do **not** require Gas Station; the repo's `vault-e2e` script uses it only for convenience on testnet. ### 2. Install Dependencies ```bash TypeScript theme={null} npm install @decibeltrade/sdk @aptos-labs/ts-sdk ``` ```bash Python theme={null} pip install aptos-sdk ``` `@aptos-labs/ts-sdk` is a peer dependency for `Ed25519Account` signing (same as the [Write SDK](/typescript-sdk/write-sdk) setup). ### 3. Set Up Your Script TypeScript examples use `DecibelWriteDex` / `DecibelReadDex`. Python examples use `aptos-sdk` with the testnet package address below. ```typescript TypeScript theme={null} import { AccountAddress, Ed25519Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk"; import { DecibelReadDex, DecibelWriteDex, extractVaultAddressFromCreateTx, getPrimarySubaccountAddr, TESTNET_CONFIG, TimeInForce, } from "@decibeltrade/sdk"; const account = new Ed25519Account({ privateKey: new Ed25519PrivateKey(process.env.PRIVATE_KEY!), }); const read = new DecibelReadDex(TESTNET_CONFIG, { nodeApiKey: process.env.APTOS_NODE_API_KEY!, }); const write = new DecibelWriteDex(TESTNET_CONFIG, account, { nodeApiKey: process.env.APTOS_NODE_API_KEY!, }); ``` ```python Python theme={null} from aptos_sdk.account import Account from aptos_sdk.account_address import AccountAddress from aptos_sdk.async_client import RestClient from aptos_sdk.bcs import Serializer from aptos_sdk.transactions import ( EntryFunction, TransactionArgument, TransactionPayload, ) import asyncio import json PACKAGE = "0xe7da2794b1d8af76532ed95f38bfdf1136abfd8ea3a240189971988a83101b7f" NODE_URL = "https://api.testnet.aptoslabs.com/v1" client = RestClient(NODE_URL) account = Account.load_key("0xYOUR_PRIVATE_KEY") ``` ### 4. Get Your Trading Account Address Your Trading Account (subaccount) holds USDC collateral used to fund a vault. ```typescript TypeScript theme={null} const primarySubaccount = write.getPrimarySubaccountAddress(account.accountAddress); console.log("Primary subaccount:", primarySubaccount); ``` ```python Python theme={null} result = await client.view( f"{PACKAGE}::dex_accounts::primary_subaccount", [], [str(account.address())], ) primary_subaccount = json.loads(result)[0] print("Primary subaccount:", primary_subaccount) ``` The primary subaccount is auto-created on your first deposit. You don't need to create it manually. ### 5. Mint Testnet USDC On testnet, mint USDC with `restricted_mint` (rate-limited per account). For the full Part 1 walkthrough, plan for **\~210 USDC** in your subaccount (see the funding table above). If mint allowance is exhausted, fund via the [Decibel UI](https://app.decibel.trade) or `write.deposit` from your wallet. Use this when `gasStationApiKey` is **not** set on your SDK config (same as testnet APT from step 1). ```typescript theme={null} const mintTx = await write.aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${write.config.deployment.package}::usdc::restricted_mint`, typeArguments: [], functionArguments: [500_000_000], // 500 USDC (6 decimals) }, }); const mintResult = await write.aptos.signAndSubmitTransaction({ signer: account, transaction: mintTx, }); await write.aptos.waitForTransaction({ transactionHash: mintResult.hash }); console.log("Minted USDC:", mintResult.hash); ``` Use this only when `gasStationApiKey` is set (matches `vault-e2e.ts` on testnet). ```typescript theme={null} const tx = await write.buildTx( { function: `${write.config.deployment.package}::usdc::restricted_mint`, typeArguments: [], functionArguments: [500_000_000], }, account.accountAddress, ); const auth = write.aptos.sign({ signer: account, transaction: tx }); const pending = await write.submitTx(tx, auth); await write.aptos.waitForTransaction({ transactionHash: pending.hash }); console.log("Minted USDC:", pending.hash); ``` If `gasStationApiKey` is set, do **not** use `aptos.transaction.build.simple` for custom Move calls like `restricted_mint` — submission will fail with *Transaction must have a fee payer*. Use the Gas Station tab above, or omit `gasStationApiKey` and pay gas with APT. ```python Python theme={null} payload = EntryFunction.natural( f"{PACKAGE}::usdc", "restricted_mint", [], [TransactionArgument(500_000_000, Serializer.u64)], ) signed_txn = await client.create_bcs_signed_transaction( account, TransactionPayload(payload) ) txn = await client.submit_and_wait_for_bcs_transaction(signed_txn) print("Minted USDC:", txn["hash"]) ``` Alternatively, fund your wallet with testnet USDC through the [Decibel UI](https://app.decibel.trade) and skip minting. On Python, creation fees and minimums depend on your target network's on-chain config. ### 6. Deposit USDC to Your Trading Account Move USDC from your wallet into your Trading Account so it can be used as vault capital. Use at least **`210_000_000`** chain units (\~210 USDC) to cover the testnet creation fee, minimum `initialFunding`, and a follow-on contribution: ```typescript TypeScript theme={null} await write.deposit(210_000_000, primarySubaccount); // ~210 USDC (6 decimals) console.log("Deposited USDC to subaccount"); ``` ```python Python theme={null} usdc_metadata = AccountAddress.from_str( # Derive USDC metadata: createObjectAddress(PACKAGE, "USDC") "0xbdabb88aa9a875f3a2ebe0974e24f3ae5e57cfd17c6abdfef8a8111f43681b7e" ) payload = EntryFunction.natural( f"{PACKAGE}::dex_accounts_entry", "deposit_to_subaccount_at", [], [ TransactionArgument(AccountAddress.from_str(primary_subaccount), Serializer.struct), TransactionArgument(usdc_metadata, Serializer.struct), TransactionArgument(210_000_000, Serializer.u64), ], ) signed_txn = await client.create_bcs_signed_transaction( account, TransactionPayload(payload) ) txn = await client.submit_and_wait_for_bcs_transaction(signed_txn) print("Deposited USDC:", txn["hash"]) ``` This USDC stays in your **primary subaccount** until create debits the creation fee and `initialFunding`. ### 7. Create and Fund Your Vault Create a vault and deposit initial capital from your Trading Account. On Aptos testnet, a **\$100 creation fee** (`100_000_000` chain units) is debited from subaccount collateral in addition to `initialFunding`. With `initialFunding` of at least `100_000_000` (100 USDC, 6 decimals), the vault activates automatically. The example below uses `200_000_000` for headroom above the minimum. ```typescript TypeScript theme={null} const createTx = await write.createVault({ subaccountAddr: primarySubaccount, contributionAssetType: write.config.deployment.usdc, vaultName: "My Trading Vault", vaultDescription: "Algorithmic strategy", vaultSocialLinks: ["https://x.com/myvault", ""], vaultShareSymbol: "MTV", feeBps: 500, // 5% performance fee feeIntervalS: 2_592_000, // 30 days contributionLockupDurationS: 0, initialFunding: 200_000_000, // 200 USDC acceptsContributions: true, delegateToCreator: true, // grants your wallet trading permissions on the vault }); const vaultAddress = extractVaultAddressFromCreateTx(createTx); console.log("Vault created:", vaultAddress); ``` ```python Python theme={null} payload = EntryFunction.natural( f"{PACKAGE}::vault_api", "create_and_fund_vault", [], [ TransactionArgument(AccountAddress.from_str(primary_subaccount), Serializer.struct), TransactionArgument(usdc_metadata, Serializer.struct), TransactionArgument("My Trading Vault", Serializer.str), TransactionArgument("Algorithmic strategy", Serializer.str), TransactionArgument(["https://x.com/myvault", ""], lambda s, v: s.sequence(v, Serializer.str)), TransactionArgument("MTV", Serializer.str), TransactionArgument("", Serializer.str), TransactionArgument("", Serializer.str), TransactionArgument(500, Serializer.u64), TransactionArgument(2592000, Serializer.u64), TransactionArgument(0, Serializer.u64), TransactionArgument(200_000_000, Serializer.u64), TransactionArgument(True, Serializer.bool), TransactionArgument(True, Serializer.bool), ], ) signed_txn = await client.create_bcs_signed_transaction( account, TransactionPayload(payload) ) txn = await client.submit_and_wait_for_bcs_transaction(signed_txn) print("Vault created:", txn["hash"]) ``` `delegateToCreator: true` grants your account permission to trade on the vault. If you set it to `false`, delegate separately in step 9 (equivalent to the repo's `vault-e2e.ts`, which uses `delegateToCreator: false` then delegates in step 9). For full parameter details, see [Create and Fund Vault](/developer-hub/on-chain/vault/create-and-fund). ### 8. Activate the Vault (if needed) If `initialFunding` was at least 100 USDC (6 decimals), skip this step. Otherwise activate after funding to the minimum: ```typescript theme={null} const activateTx = await write.buildActivateVaultTx({ vaultAddress, signerAddress: account.accountAddress, }); const activateResult = await write.aptos.signAndSubmitTransaction({ signer: account, transaction: activateTx, }); await write.aptos.waitForTransaction({ transactionHash: activateResult.hash }); console.log("Vault activated:", activateResult.hash); ``` ```typescript theme={null} const activateTx = await write.buildActivateVaultTx({ vaultAddress, signerAddress: account.accountAddress, }); const auth = write.aptos.sign({ signer: account, transaction: activateTx }); const pending = await write.submitTx(activateTx, auth); await write.aptos.waitForTransaction({ transactionHash: pending.hash }); console.log("Vault activated:", pending.hash); ``` ```python Python theme={null} payload = EntryFunction.natural( f"{PACKAGE}::vault_api", "activate_vault", [], [TransactionArgument(AccountAddress.from_str(vault_address), Serializer.struct)], ) signed_txn = await client.create_bcs_signed_transaction( account, TransactionPayload(payload) ) txn = await client.submit_and_wait_for_bcs_transaction(signed_txn) print("Vault activated:", txn["hash"]) ``` For full parameter details, see [Activate Vault](/developer-hub/on-chain/vault/activate). ### 9. Delegate Trading (optional) Skip this step if you set `delegateToCreator: true` in step 7. To grant trading permissions to another address (e.g. a bot wallet): ```typescript theme={null} const delegateTx = await write.buildDelegateDexActionsToTx({ vaultAddress, accountToDelegateTo: botWalletAddress, signerAddress: account.accountAddress, }); const delegateResult = await write.aptos.signAndSubmitTransaction({ signer: account, transaction: delegateTx, }); await write.aptos.waitForTransaction({ transactionHash: delegateResult.hash }); console.log("Delegated trading:", delegateResult.hash); ``` ```typescript theme={null} const delegateBuilt = await write.buildDelegateDexActionsToTx({ vaultAddress, accountToDelegateTo: botWalletAddress, signerAddress: account.accountAddress, }); const delegateAuth = write.aptos.sign({ signer: account, transaction: delegateBuilt }); const delegatePending = await write.submitTx(delegateBuilt, delegateAuth); await write.aptos.waitForTransaction({ transactionHash: delegatePending.hash }); console.log("Delegated trading:", delegatePending.hash); ``` ```python Python theme={null} def serialize_option_u64(ser, val): """Serialize an optional u64: None = empty option, int = some(value)""" if val is None: ser.u8(0) # None variant else: ser.u8(1) # Some variant ser.u64(val) payload = EntryFunction.natural( f"{PACKAGE}::vault_admin_api", "delegate_dex_actions_to", [], [ TransactionArgument(AccountAddress.from_str(vault_address), Serializer.struct), TransactionArgument(AccountAddress.from_str(bot_wallet_address), Serializer.struct), TransactionArgument(None, serialize_option_u64), # No expiration ], ) signed_txn = await client.create_bcs_signed_transaction( account, TransactionPayload(payload) ) txn = await client.submit_and_wait_for_bcs_transaction(signed_txn) print("Delegated trading:", txn["hash"]) ``` For full parameter details, see [Delegate DEX Actions](/developer-hub/on-chain/vault/delegate-dex-actions). ### 10. Place an Order as the Vault Vault trading uses the same `placeOrder` API as a normal Trading Account. The difference is the `subaccountAddr`: pass the vault's portfolio subaccount (derived from the vault object address), not your wallet's primary subaccount. You must have delegated trading first (`delegateToCreator: true` in step 7, or step 9). Use a market that exists on your network (this example uses `APT/USD`). ```typescript TypeScript theme={null} const vaultSubaccount = getPrimarySubaccountAddr( AccountAddress.fromString(vaultAddress), write.config.compatVersion, write.config.deployment.package, ); const markets = await read.markets.getAll(); const marketPrices = await read.marketPrices.getAll(); const market = markets.find((m) => m.market_name === "APT/USD"); // use a live market on your network if (!market) throw new Error("Market not found"); const midPx = marketPrices.find((p) => p.market === market.market_addr)?.mid_px; if (midPx == null) throw new Error("No mid price for market"); // Convert human-readable amounts to chain units — see formatting guide function amountToChainUnits(amount: number, decimals: number) { return Math.floor(amount * 10 ** decimals); } const orderResult = await write.placeOrder({ marketName: market.market_name, price: amountToChainUnits(midPx, market.px_decimals), size: market.min_size, isBuy: true, timeInForce: TimeInForce.ImmediateOrCancel, isReduceOnly: false, subaccountAddr: vaultSubaccount, tickSize: market.tick_size, }); if (orderResult.success) { console.log("Vault order placed:", orderResult.transactionHash); } else { console.error("Order failed:", orderResult.error); } ``` ```python Python theme={null} # Use the on-chain place_order_to_subaccount flow with the vault portfolio subaccount. # See /developer-hub/on-chain/order-management/place-order ``` See [Write SDK — Trading on behalf of a vault](/typescript-sdk/write-sdk#trading-on-behalf-of-a-vault) for TWAP, TP/SL, and cancellation on the vault subaccount (TypeScript). Verify your vault is live. Browse to [app.decibel.trade/vaults](https://app.decibel.trade/vaults) and search for your vault name. You can also query it via the REST API to confirm it's active and accepting contributions. ## Part 2: How Vaults Work A vault pools capital under a single manager. The manager trades with the pooled funds, and profits (after fees) are distributed to all shareholders proportionally. Contributors receive fungible share tokens representing their claim on the vault's net assets. See [Vaults for Traders](/for-traders/vaults) for the full contributor perspective. ### Vault Lifecycle | Phase | What happens | | -------------- | ------------------------------------------------------------------------------------------------------------------------------- | | Creation | Manager creates the vault, sets fee parameters, and deposits initial capital | | Pre-activation | Vault exists but doesn't accept contributions. Manager must fund it to the minimum (\$100) | | Activation | Manager activates the vault (or it auto-activates if funded with >= \$100 at creation). It can now accept outside contributions | | Active trading | Manager (or delegate) trades with pooled capital. Contributors can join or redeem | | Ongoing | Fees are crystallized at each interval. Shares are minted/burned as contributors join/leave | ### Interval-Based Performance Fees Vaults use an interval-based fee model. There is no high watermark or cumulative tracking. 1. When a vault is created, the manager sets a fee rate (0-10%) and a fee interval (30-365 days). 2. At the end of each interval, the protocol compares the vault's current NAV to its NAV at the start of that interval. 3. If the vault profited during that interval, the manager receives their fee percentage as newly minted shares. 4. If the vault lost money or broke even, the manager receives nothing for that interval. 5. The next interval starts fresh. There is no carry-forward of losses from previous intervals. Each interval is independent. If a vault loses 20% in one interval and gains 25% in the next, the manager earns fees on the full 25% gain in the second interval, even though the vault hasn't fully recovered. This is different from a high watermark model. ### Key Parameters These are the protocol-enforced limits. Vault managers choose values within these ranges at creation time. | Parameter | Range / Value | | ----------------------- | ----------------------------------------------------- | | Performance fee | 0-10% (0-1000 bps) | | Fee interval | 30-365 days | | Min manager capital | Lesser of 5% of vault NAV or \$100,000 | | Min activation funding | \$100 | | Min contribution | \$10 | | Min redemption | \$5 | | Max contribution lockup | 0-7 days | | Vault creation fee | Configurable per network (**\$100 on Aptos testnet**) | ### Shares as Fungible Tokens When you contribute to a vault, you receive fungible share tokens on Aptos. These shares are transferable, can be used as collateral in other DeFi protocols, and can be traded on secondary markets. See [Fungible Token Ownership](/for-traders/vaults#fungible-token-ownership) for details. ### Protocol Vault (DLP) vs User Vaults Decibel runs one special vault, the [Decibel Liquidity Provider (DLP)](/for-traders/dlp-vault), alongside user-created vaults. Both use the same onchain infrastructure. | | DLP Vault | User Vaults | | ------------------- | -------------------- | ----------------------------- | | Manager | Protocol (automated) | Any user | | Strategy | Market making | Manager's discretion | | Contribution lockup | 72 hours | 0-7 days (manager-configured) | | Fee structure | 0% | Manager-defined (0-10%) | ## Part 3: Advanced Operations ### Contributing to an Existing Vault Anyone can contribute to an active vault that accepts contributions. The minimum contribution is \$10 USDC (`10_000_000` chain units). Contributions go through your Trading Account (subaccount). After creating a vault in Part 1, an additional `depositToVault` matches the e2e smoke test's follow-on contribution step. ```typescript TypeScript theme={null} await write.depositToVault({ vaultAddress, amount: 50_000_000, // 50 USDC (6 decimals) subaccountAddr: primarySubaccount, }); console.log("Contributed to vault"); ``` ```python Python theme={null} payload = EntryFunction.natural( f"{PACKAGE}::dex_accounts_entry", "contribute_to_vault", [], [ TransactionArgument(AccountAddress.from_str(primary_subaccount), Serializer.struct), TransactionArgument(AccountAddress.from_str(vault_address), Serializer.struct), TransactionArgument(usdc_metadata, Serializer.struct), TransactionArgument(50_000_000, Serializer.u64), ], ) signed_txn = await client.create_bcs_signed_transaction( account, TransactionPayload(payload) ) txn = await client.submit_and_wait_for_bcs_transaction(signed_txn) print("Contributed to vault:", txn["hash"]) ``` If the vault has a contribution lockup configured, you cannot redeem your shares until the lockup period expires. For full parameter details, see [Contribute to Vault](/developer-hub/on-chain/vault/contribute). ### Redeeming Shares To withdraw from a vault, redeem your share tokens for the underlying USDC. The minimum redemption is \$5 (`5_000_000` share units at 6 decimals). The protocol may close up to 10% of positions per redemption at up to 2% slippage to free capital. Query your share balance on the **contributor subaccount** (not the wallet address), then redeem at least the minimum: ```typescript TypeScript theme={null} const performances = await read.vaults.getUserPerformancesOnVaults({ ownerAddr: primarySubaccount, }); const shares = performances.find((p) => p.vault.address === vaultAddress)?.current_num_shares ?? 0; await write.withdrawFromVault({ vaultAddress, shares: Math.max(5_000_000, Math.floor(shares * 0.1)), // partial redeem, min $5 subaccountAddr: primarySubaccount, }); console.log("Redeemed from vault"); ``` ```python Python theme={null} payload = EntryFunction.natural( f"{PACKAGE}::dex_accounts_entry", "redeem_from_vault", [], [ TransactionArgument(AccountAddress.from_str(primary_subaccount), Serializer.struct), TransactionArgument(AccountAddress.from_str(vault_address), Serializer.struct), TransactionArgument(10_000_000, Serializer.u64), ], ) signed_txn = await client.create_bcs_signed_transaction( account, TransactionPayload(payload) ) txn = await client.submit_and_wait_for_bcs_transaction(signed_txn) print("Redeemed from vault:", txn["hash"]) ``` For full parameter details, see [Redeem from Vault](/developer-hub/on-chain/vault/redeem). ### Querying Vault Data ```typescript TypeScript theme={null} const vaults = await read.vaults.getVaults({ vaultType: "user", limit: 20 }); const owned = await read.vaults.getUserOwnedVaults({ ownerAddr: account.accountAddress.toString(), // wallet — vaults you created }); const performances = await read.vaults.getUserPerformancesOnVaults({ ownerAddr: primarySubaccount, // subaccount — shares you hold as a contributor }); const sharePrice = await read.vaults.getVaultSharePrice({ vaultAddress }); const maxInstantRedeem = await read.vaults.getMaxSynchronousRedemption({ vaultAddress }); ``` ```python Python theme={null} # Query vault listings and performance via the REST API (see link below). ``` Vault listings and performance are also available through the REST API. See [vault endpoints](/api-reference/vaults/get-account-owned-vaults). ### Trading on Behalf of a Vault The vault manager (or any delegated account) places orders with `write.placeOrder` and `subaccountAddr` set to the vault portfolio subaccount (see [Part 1, step 10](#10-place-an-order-as-the-vault) and [Write SDK — Trading on behalf of a vault](/typescript-sdk/write-sdk#trading-on-behalf-of-a-vault)). 1. At creation: `delegateToCreator: true` grants the creator trading permissions. 2. After creation: use `buildDelegateDexActionsToTx` to delegate to a bot wallet. 3. Delegations can optionally include an expiration timestamp. 4. The vault owner can revoke delegations on-chain at any time. The same order types as regular [Trading Accounts](/for-traders/vaults) (limit, market, TWAP, TP/SL) work when `subaccountAddr` is the vault subaccount. ## What's Next Full parameter docs for [Create and Fund](/developer-hub/on-chain/vault/create-and-fund), [Activate](/developer-hub/on-chain/vault/activate), [Contribute](/developer-hub/on-chain/vault/contribute), [Redeem](/developer-hub/on-chain/vault/redeem), and [Delegate](/developer-hub/on-chain/vault/delegate-dex-actions). See [Vaults for Traders](/for-traders/vaults) for the contributor perspective and [Fees](/for-traders/fees) for the full fee breakdown. Learn about the protocol-owned liquidity vault and its backstop role on the [DLP Vault](/for-traders/dlp-vault) page. See [Write SDK — Vault transactions](/typescript-sdk/write-sdk#vault-transactions) and [Trading on behalf of a vault](/typescript-sdk/write-sdk#trading-on-behalf-of-a-vault). Optional end-to-end smoke: `cd typescript/packages/e2e && pnpm start:vault-e2e`. # Create Trading Account Source: https://docs.decibel.trade/developer-hub/on-chain/account-management/create-subaccount Create a new Trading Account Each user can have multiple Trading Accounts for different trading strategies. In the SDK, API, and Move contracts, Trading Accounts are called `subaccount`. The endpoint is `/subaccounts`, the function is `create_new_subaccount`, and the SDK method is `createSubaccount`. We refer to them as Trading Accounts. **Function:** ``` {package}::dex_accounts_entry::create_new_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "create_new_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: ["&signer"], return: [], }; ``` **Parameters:** * `signer` - The account signer (your account) **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::create_new_subaccount`, typeArguments: [], functionArguments: [], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::create_new_subaccount", "type_arguments": [], "function_arguments": [], }, ) ``` # Delegate Trading To Source: https://docs.decibel.trade/developer-hub/on-chain/account-management/delegate-trading Delegate trading permissions to another account **Function:** ``` {package}::dex_accounts_entry::delegate_all_trading_to_for_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "delegate_all_trading_to_for_subaccount", visibility: "friend", is_entry: true, is_view: false, generic_type_params: [], params: ["&signer", "address", "address", "0x1::option::Option"], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount_address` - The Trading Account address * `account_to_delegate_to` - Address to delegate trading to * `expiration_timestamp_secs` - Optional expiration timestamp `` `>` `` **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::delegate_all_trading_to_for_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddress "0x789...xyz", // delegateToAddress 1735689600, // expirationTimestamp (optional, Unix timestamp in seconds) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::delegate_all_trading_to_for_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddress "0x789...xyz", # delegateToAddress 1735689600, # expirationTimestamp (optional, Unix timestamp in seconds) ], }, ) ``` # Deposit to Trading Account Source: https://docs.decibel.trade/developer-hub/on-chain/account-management/deposit Deposit collateral to a Trading Account **Function:** ``` {package}::dex_accounts_entry::deposit_to_subaccount_at ``` **ABI Object (deposit\_to\_subaccount\_at):** ```typescript theme={null} const functionAbi: MoveFunction = { name: "deposit_to_subaccount_at", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "address", "0x1::object::Object<0x1::fungible_asset::Metadata>", "u64", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount_address` - The Trading Account address to deposit to * `asset_metadata` - The fungible asset metadata (USDC) * `amount` - Amount in smallest unit (e.g., 1000000 = 1 USDC if 6 decimals) **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::deposit_to_subaccount_at`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // usdcAddress (USDC metadata object address) 1000000, // amount (1 USDC with 6 decimals) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::deposit_to_subaccount_at", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # usdcAddress (USDC metadata object address) 1000000, # amount (1 USDC with 6 decimals) ], }, ) ``` # Revoke Delegation Source: https://docs.decibel.trade/developer-hub/on-chain/account-management/revoke-delegation Revoke trading delegation from an account **Function:** ``` {package}::dex_accounts_entry::revoke_delegation ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "revoke_delegation", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "address", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `account_to_revoke` - Address to revoke delegation from **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::revoke_delegation`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x789...xyz", // accountToRevoke (address to revoke delegation from) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::revoke_delegation", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x789...xyz", # accountToRevoke (address to revoke delegation from) ], }, ) ``` # Withdraw from Trading Account Source: https://docs.decibel.trade/developer-hub/on-chain/account-management/withdraw Withdraw collateral from a Trading Account **Function:** ``` {package}::dex_accounts_entry::withdraw_from_cross_collateral ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "withdraw_from_cross_collateral", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<0x1::fungible_asset::Metadata>", "u64", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `asset_metadata` - The fungible asset metadata (USDC) * `amount` - Amount to withdraw in smallest unit **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::withdraw_from_cross_collateral`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr usdcMetadata, // USDC metadata object 500000, // amount (0.5 USDC with 6 decimals) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::withdraw_from_cross_collateral", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr usdc_metadata, # USDC metadata object 500000, # amount (0.5 USDC with 6 decimals) ], }, ) ``` # Approve Max Builder Fee Source: https://docs.decibel.trade/developer-hub/on-chain/builder-fee/approve-max-builder-fee Approve maximum builder fee for a Trading Account **Function:** ``` {package}::dex_accounts_entry::approve_max_builder_fee_for_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "approve_max_builder_fee_for_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "address", "u64", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `builder_addr` - The builder address * `max_fee` - Maximum fee in basis points (u64) **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::approve_max_builder_fee_for_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0xabc...123", // builderAddr (builder/referrer address) 50, // maxFee (50 basis points = 0.5%) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::approve_max_builder_fee_for_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0xabc...123", # builderAddr (builder/referrer address) 50, # maxFee (50 basis points = 0.5%) ], }, ) ``` # Revoke Max Builder Fee Source: https://docs.decibel.trade/developer-hub/on-chain/builder-fee/revoke-max-builder-fee Revoke maximum builder fee approval for a Trading Account **Function:** ``` {package}::dex_accounts_entry::revoke_max_builder_fee_for_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "revoke_max_builder_fee_for_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "address", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `builder_addr` - The builder address to revoke **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::revoke_max_builder_fee_for_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0xabc...123", // builderAddr (builder address to revoke) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::revoke_max_builder_fee_for_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0xabc...123", # builderAddr (builder address to revoke) ], }, ) ``` # Cancel Bulk Order Source: https://docs.decibel.trade/developer-hub/on-chain/order-management/cancel-bulk-order Cancels a bulk order for the specified account. Equivalent to submitting a bulk order with no price levels. **Function:** ``` {package}::dex_accounts_entry::cancel_bulk_order_to_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "cancel_bulk_order_to_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::perp_market::PerpMarket>", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `market` - The PerpMarket object **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::cancel_bulk_order_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (PerpMarket object address) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::cancel_bulk_order_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (PerpMarket object address) ], }, ) ``` # Cancel Client Order Source: https://docs.decibel.trade/developer-hub/on-chain/order-management/cancel-client-order Cancel an order by client-assigned order ID **Function:** ``` {package}::dex_accounts_entry::cancel_client_order_to_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "cancel_client_order_to_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::string::String", "0x1::object::Object<{package}::perp_market::PerpMarket>", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `client_order_id` - The client-assigned order ID (String) * `market` - The PerpMarket object **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::cancel_client_order_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "my-order-123", // clientOrderId (String) "0x456...def", // marketAddr (PerpMarket object address) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::cancel_client_order_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "my-order-123", # clientOrderId (String) "0x456...def", # marketAddr (PerpMarket object address) ], }, ) ``` # Cancel Order Source: https://docs.decibel.trade/developer-hub/on-chain/order-management/cancel-order Cancel an order by order ID **Function:** ``` {package}::dex_accounts_entry::cancel_order_to_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "cancel_order_to_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "u128", "0x1::object::Object<{package}::perp_market::PerpMarket>", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `order_id` - The order ID to cancel (u128) * `market` - The PerpMarket object **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::cancel_order_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr 12345678901234567890, // orderId (u128) "0x456...def", // marketAddr (PerpMarket object address) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::cancel_order_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr 12345678901234567890, # orderId (u128) "0x456...def", # marketAddr (PerpMarket object address) ], }, ) ``` # Cancel Spot Bulk Order Source: https://docs.decibel.trade/developer-hub/on-chain/order-management/cancel-spot-bulk-order Cancel a full spot ladder or a single price level Two entry functions are available: cancel the entire resting ladder, or remove a single price level and leave the rest in place. ## Cancel the Full Ladder **Function:** ``` {package}::dex_accounts_spot_entry::cancel_spot_bulk_order_to_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "cancel_spot_bulk_order_to_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::spot_market::SpotMarket>", ], return: [], }; ``` **Parameters:** * `auth` - The account signer * `subaccount` - The Trading Account object * `market` - The SpotMarket object ## Cancel a Single Price Level **Function:** ``` {package}::dex_accounts_spot_entry::cancel_spot_bulk_order_at_price_level_to_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "cancel_spot_bulk_order_at_price_level_to_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::spot_market::SpotMarket>", "u64", "bool", ], return: [], }; ``` **Parameters:** * `auth` - The account signer * `subaccount` - The Trading Account object * `market` - The SpotMarket object * `price` - The price level to cancel, in raw quote units `` `` `` * `is_bid` - True to cancel the bid at that price, false for the ask For wallet-direct ladders, use `cancel_spot_bulk_order` and `cancel_spot_bulk_order_at_price_level`, which take the same arguments without the `subaccount` parameter. **Example:** ```typescript Typescript theme={null} // Cancel the entire ladder const cancelAll = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_spot_entry::cancel_spot_bulk_order_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (SpotMarket object address) ], }, }); // Cancel only the ask resting at one price level const cancelLevel = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_spot_entry::cancel_spot_bulk_order_at_price_level_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (SpotMarket object address) 45100000, // price (raw quote units) false, // isBid (false cancels the ask at that price) ], }, }); ``` ```python Python theme={null} # Cancel the entire ladder cancel_all = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_spot_entry::cancel_spot_bulk_order_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (SpotMarket object address) ], }, ) # Cancel only the ask resting at one price level cancel_level = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_spot_entry::cancel_spot_bulk_order_at_price_level_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (SpotMarket object address) 45100000, # price (raw quote units) False, # isBid (false cancels the ask at that price) ], }, ) ``` # Cancel Spot Order Source: https://docs.decibel.trade/developer-hub/on-chain/order-management/cancel-spot-order Cancel a resting order on a spot market **Function:** ``` {package}::dex_accounts_spot_entry::cancel_spot_order_to_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "cancel_spot_order_to_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::spot_market::SpotMarket>", "u128", ], return: [], }; ``` **Parameters:** * `auth` - The account signer * `subaccount` - The Trading Account object * `market` - The SpotMarket object * `order_id` - The spot order ID to cancel `` `` `` Spot has no client-assigned order IDs, so cancellation is by `order_id` only. There is no spot equivalent of `cancel_client_order`. Canceling releases the order's escrowed funds — quote for a bid, base for an ask — back to the account it was funded from. To cancel an order placed directly from a wallet, use `cancel_spot_order`, which takes the same arguments without the `subaccount` parameter. **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_spot_entry::cancel_spot_order_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (SpotMarket object address) "12345678901234567890", // orderId (u128 as string) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_spot_entry::cancel_spot_order_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (SpotMarket object address) "12345678901234567890", # orderId (u128 as string) ], }, ) ``` # Cancel TWAP Order Source: https://docs.decibel.trade/developer-hub/on-chain/order-management/cancel-twap-order Cancel a TWAP order **Function:** ``` {package}::dex_accounts_entry::cancel_twap_orders_to_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "cancel_twap_orders_to_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::perp_market::PerpMarket>", "u128", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `market` - The PerpMarket object * `order_id` - The TWAP order ID (u128) **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::cancel_twap_orders_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (PerpMarket object address) 12345678901234567890, // orderId (u128) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::cancel_twap_orders_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (PerpMarket object address) 12345678901234567890, # orderId (u128) ], }, ) ``` # Place Bulk Order Source: https://docs.decibel.trade/developer-hub/on-chain/order-management/place-bulk-order Place a post-only bulk order on the exchange The **Bulk Order API** allows a client to submit and manage multiple limit orders (both bids and asks) in a single atomic transaction. Eac account can have at most one Bulk Order per market. This API **cancels all existing resting liquidity** for the market provided and **replaces it with the new bulk set of orders** (bids and asks). Partial failures (e.g., an order that cannot be posted due to a `PostOnly` violation) do **not revert the transaction** — that particular order will simply be skipped or partially placed. Cancelled price levels and sizes will be returned explicitly in the update event. \*\* NOTE \*\* * Bulk Order Placements with a non-increasing `sequence_number` will be rejected. * Order updates that reduce size will maintain its position in the matching queue, order updates that increase size will be moved to the end of the matching queue. **Function:** ``` {package}::dex_accounts_entry::place_bulk_orders_to_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "place_bulk_orders_to_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::perp_market::PerpMarket>", "u64", "vector", "vector", "vector", "vector", "0x1::option::Option
", "0x1::option::Option", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `market` - The PerpMarket object * `sequence_number` - The monotonically increasing number associated with this order * `bid_prices` - `` `vector` `` - Array of bid prices in chain units * `bid_sizes` - `` `vector` `` - Array of bid sizes in chain units * `ask_prices` - `` `vector` `` - Array of ask prices in chain units * `ask_sizes` - `` `vector` `` - Array of ask sizes in chain units * `builder_address` - Optional builder address `` `>` `` * `builder_fees` - Optional builder fee `` `>` `` ## Time in Force **Bulk Orders are Post-Only limit orders**. **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::place_bulk_orders_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (PerpMarket object address) 1, // sequenceNumber (must be monotonically increasing) [5670000000, 5680000000, 5690000000], // bidPrices (in chain units) [1000000000, 2000000000, 3000000000], // bidSizes (in chain units) [5710000000, 5720000000, 5730000000], // askPrices (in chain units) [1000000000, 2000000000, 3000000000], // askSizes (in chain units) null, // builderAddress (optional) null, // builderFees (optional) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::place_bulk_orders_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (PerpMarket object address) 1, # sequenceNumber (must be monotonically increasing) [5670000000, 5680000000, 5690000000], # bidPrices (in chain units) [1000000000, 2000000000, 3000000000], # bidSizes (in chain units) [5710000000, 5720000000, 5730000000], # askPrices (in chain units) [1000000000, 2000000000, 3000000000], # askSizes (in chain units) None, # builderAddress (optional) None, # builderFees (optional) ], }, ) ``` # Place Order Source: https://docs.decibel.trade/developer-hub/on-chain/order-management/place-order Place a limit order on the exchange **Function:** ``` {package}::dex_accounts_entry::place_order_to_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "place_order_to_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::perp_market::PerpMarket>", "u64", "u64", "bool", "u8", "bool", "0x1::option::Option<0x1::string::String>", "0x1::option::Option", "0x1::option::Option", "0x1::option::Option", "0x1::option::Option", "0x1::option::Option", "0x1::option::Option
", "0x1::option::Option", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `market` - The PerpMarket object * `price` - Order price `` `` `` * `size` - Order size `` `` `` * `is_buy` - True for buy order, false for sell order * `time_in_force` - Time in force `` `` ``: 0 = GoodTillCanceled, 1 = PostOnly, 2 = ImmediateOrCancel * `is_reduce_only` - Whether order can only reduce position size * `client_order_id` - Optional client-assigned order ID `` `>` `` * `stop_price` - Optional stop price `` `>` `` * `tp_trigger_price` - Optional take-profit trigger price `` `>` `` * `tp_limit_price` - Optional take-profit limit price `` `>` `` * `sl_trigger_price` - Optional stop-loss trigger price `` `>` `` * `sl_limit_price` - Optional stop-loss limit price `` `>` `` * `builder_address` - Optional builder/referrer address `` `>` `` * `builder_fees` - Optional builder fee in basis points `` `>` `` ## Time in Force Options When placing orders, you can specify different execution types using the `time_in_force` parameter: * **`0` (GoodTillCanceled)** - Order stays active until it is filled or manually canceled * **`1` (PostOnly)** - Order only adds liquidity to the order book (becomes a maker order). If the order would execute immediately, it is canceled * **`2` (ImmediateOrCancel)** - Order executes immediately at the best available price. Any unfilled portion is canceled **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::place_order_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (PerpMarket object address) 5670000000, // price (5.67 with 9 decimals) 1000000000, // size (1.0 with 9 decimals) true, // isBuy (true for buy, false for sell) 0, // timeInForce (0 = GoodTillCanceled, 1 = PostOnly, 2 = ImmediateOrCancel) false, // isReduceOnly "my-order-123", // clientOrderId (optional) null, // stopPrice (optional) null, // tpTriggerPrice (optional) null, // tpLimitPrice (optional) null, // slTriggerPrice (optional) null, // slLimitPrice (optional) null, // builderAddress (optional) null, // builderFees (optional) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::place_order_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (PerpMarket object address) 5670000000, # price (5.67 with 9 decimals) 1000000000, # size (1.0 with 9 decimals) True, # isBuy (true for buy, false for sell) 0, # timeInForce (0 = GoodTillCanceled, 1 = PostOnly, 2 = ImmediateOrCancel) False, # isReduceOnly "my-order-123", # clientOrderId (optional) None, # stopPrice (optional) None, # tpTriggerPrice (optional) None, # tpLimitPrice (optional) None, # slTriggerPrice (optional) None, # slLimitPrice (optional) None, # builderAddress (optional) None, # builderFees (optional) ], }, ) ``` # Place Spot Bulk Order Source: https://docs.decibel.trade/developer-hub/on-chain/order-management/place-spot-bulk-order Place a two-sided ladder of orders on a spot market in one transaction **Function:** ``` {package}::dex_accounts_spot_entry::place_spot_bulk_order_to_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "place_spot_bulk_order_to_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::spot_market::SpotMarket>", "u64", "vector", "vector", "vector", "vector", "0x1::option::Option
", "0x1::option::Option", ], return: [], }; ``` **Parameters:** * `auth` - The account signer * `subaccount` - The Trading Account object * `market` - The SpotMarket object * `sequence_number` - Monotonic sequence number used to replace the resting ladder `` `` `` * `bid_prices` - Bid prices in raw quote units `` `>` `` * `bid_sizes` - Bid sizes in raw base units `` `>` `` * `ask_prices` - Ask prices in raw quote units `` `>` `` * `ask_sizes` - Ask sizes in raw base units `` `>` `` * `builder_address` - Optional builder/referrer address `` `>` `` * `builder_fees` - Optional builder fee cap `` `>` `` A single builder code applies to every level of the bulk order. Each call **replaces** the account's entire resting ladder on that market rather than adding to it. Use a strictly increasing `sequence_number` so stale submissions are rejected rather than reinstating an old ladder. Spot bulk orders are funded from the primary fungible store (PFS) only — unlike single spot orders, they do not fall back to collateral-backed storage. The transaction aborts if PFS is short on either side of the ladder. To place a ladder directly from a wallet, use `place_spot_bulk_order`, which takes the same arguments without the `subaccount` parameter. **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_spot_entry::place_spot_bulk_order_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (SpotMarket object address) 7, // sequenceNumber (must increase on each replacement) [44950000, 44900000], // bidPrices (raw quote units) [20000, 30000], // bidSizes (raw base units) [45100000, 45200000], // askPrices (raw quote units) [15000, 25000], // askSizes (raw base units) null, // builderAddress (optional) null, // builderFees (optional) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_spot_entry::place_spot_bulk_order_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (SpotMarket object address) 7, # sequenceNumber (must increase on each replacement) [44950000, 44900000], # bidPrices (raw quote units) [20000, 30000], # bidSizes (raw base units) [45100000, 45200000], # askPrices (raw quote units) [15000, 25000], # askSizes (raw base units) None, # builderAddress (optional) None, # builderFees (optional) ], }, ) ``` # Place Spot Order Source: https://docs.decibel.trade/developer-hub/on-chain/order-management/place-spot-order Place a limit order on a spot market **Function:** ``` {package}::dex_accounts_spot_entry::place_spot_order_to_subaccount ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "place_spot_order_to_subaccount", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::spot_market::SpotMarket>", "u64", "u64", "bool", "u8", "0x1::option::Option
", "0x1::option::Option", ], return: [], }; ``` **Parameters:** * `auth` - The account signer * `subaccount` - The Trading Account object * `market` - The SpotMarket object * `price` - Order price in raw quote units, aligned to `tick_size` `` `` `` * `orig_size` - Order size in raw base units, aligned to `lot_size` `` `` `` * `is_bid` - True for a bid (buy), false for an ask (sell) * `time_in_force` - Time in force `` `` ``: 0 = GoodTillCanceled, 1 = PostOnly, 2 = ImmediateOrCancel * `builder_address` - Optional builder/referrer address `` `>` `` * `builder_fees` - Optional builder fee cap `` `>` `` For converting human-readable prices and sizes to raw units, see [Formatting Prices and Sizes](/developer-hub/on-chain/overview/formatting-prices-sizes). A spot market address is not interchangeable with a perp market address. A spot BTC market and a perp BTC market are separate markets with separate addresses — pass the spot market you want. Spot has no reduce-only flag, client order ID, or TP/SL parameters. ## Time in Force Options * **`0` (GoodTillCanceled)** - Order stays active until it is filled or manually canceled * **`1` (PostOnly)** - Order only adds liquidity to the order book (becomes a maker order). If the order would execute immediately, it is canceled * **`2` (ImmediateOrCancel)** - Order executes immediately at the best available price. Any unfilled portion is canceled ## Collateral and Funding Spot orders are fully collateralized before they reach the book: a bid escrows the quote asset, an ask escrows the base asset. Funds are sourced from the subaccount's primary fungible store (PFS) first, then the remainder from collateral-backed storage (CBS) when the asset is CBS-supported. If the CBS withdrawal is rate-limited, the order is queued in `spot_pending_cbs_queue` and placed once `process_pending_withdrawals` drains the request — so a successful transaction does not always mean the order is immediately resting on the book. Placement aborts with `EUNDELIVERABLE_PROCEEDS` if the projected maximum fill proceeds could not be delivered to your account (neither CBS nor PFS deposits would succeed). This is a pre-trade gate: check `get_max_proceeds_balance` and `can_make_spot_deposit` if you need to predict it. To trade directly from a wallet instead of a Trading Account, use `place_spot_order`, which takes the same arguments without the `subaccount` parameter. **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_spot_entry::place_spot_order_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (SpotMarket object address) 45000000, // price (raw quote units, aligned to tickSize) 100000, // origSize (raw base units, aligned to lotSize) true, // isBid (true for buy, false for sell) 0, // timeInForce (0 = GoodTillCanceled, 1 = PostOnly, 2 = ImmediateOrCancel) null, // builderAddress (optional) null, // builderFees (optional) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_spot_entry::place_spot_order_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (SpotMarket object address) 45000000, # price (raw quote units, aligned to tickSize) 100000, # origSize (raw base units, aligned to lotSize) True, # isBid (true for buy, false for sell) 0, # timeInForce (0 = GoodTillCanceled, 1 = PostOnly, 2 = ImmediateOrCancel) None, # builderAddress (optional) None, # builderFees (optional) ], }, ) ``` # Place TWAP Order Source: https://docs.decibel.trade/developer-hub/on-chain/order-management/place-twap-order Place a Time-Weighted Average Price (TWAP) order **Function:** ``` {package}::dex_accounts_entry::place_twap_order_to_subaccount_v2 ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "place_twap_order_to_subaccount_v2", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::perp_market::PerpMarket>", "u64", "bool", "bool", "0x1::option::Option<0x1::string::String>", "u64", "u64", "0x1::option::Option
", "0x1::option::Option", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `market` - The PerpMarket object * `size` - Total size to execute (u64) * `is_buy` - True for buy, false for sell * `is_reduce_only` - Whether order can only reduce position * `client_order_id` - Optional client-assigned order ID `` `>` `` * `twap_frequency_seconds` - How often to execute sub-orders (u64) * `twap_duration_seconds` - Total duration for TWAP order (u64) * `builder_address` - Optional builder address `` `>` `` * `builder_fees` - Optional builder fee `` `>` `` **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::place_twap_order_to_subaccount_v2`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (PerpMarket object address) 10000000000, // size (10.0 with 9 decimals) true, // isBuy (true for buy, false for sell) false, // isReduceOnly null, // clientOrderId (optional) 60, // twapFrequencySeconds (execute every 60 seconds) 3600, // twapDurationSeconds (total duration: 1 hour) null, // builderAddress (optional) null, // builderFees (optional) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::place_twap_order_to_subaccount_v2", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (PerpMarket object address) 10000000000, # size (10.0 with 9 decimals) True, # isBuy (true for buy, false for sell) False, # isReduceOnly None, # clientOrderId (optional) 60, # twapFrequencySeconds (execute every 60 seconds) 3600, # twapDurationSeconds (total duration: 1 hour) None, # builderAddress (optional) None, # builderFees (optional) ], }, ) ``` # Contract Addresses & Helpers Source: https://docs.decibel.trade/developer-hub/on-chain/overview/contract-reference Package addresses and helper functions for building Decibel transactions This page provides the contract addresses and common helper functions you'll need when building transactions directly. ## Package Address All Decibel transactions use the following package address: ```bash Mainnet theme={null} 0x50ead22afd6ffd9769e3b3d6e0e64a2a350d68e8b102c4e72e33d0b8cfdfdb06 ``` ```bash Testnet theme={null} 0xe7da2794b1d8af76532ed95f38bfdf1136abfd8ea3a240189971988a83101b7f ``` ## Helper Functions ### Get Market Address ```typescript Typescript theme={null} import { AccountAddress, createObjectAddress, MoveString, } from "@aptos-labs/ts-sdk"; function getMarketAddr( marketName: string, perpEngineGlobal: string ): AccountAddress { const marketNameBytes = new MoveString(marketName).bcsToBytes(); return createObjectAddress( AccountAddress.fromString(perpEngineGlobal), marketNameBytes ); } ``` ```python Python theme={null} from aptos_sdk.account_address import AccountAddress, create_object_address from aptos_sdk.bcs import Serializer def get_market_addr( market_name: str, perp_engine_global: str ) -> AccountAddress: # Serialize market name as Move string (length-prefixed UTF-8) serializer = Serializer() serializer.str(market_name) market_name_bytes = serializer.output() return create_object_address( AccountAddress.from_str(perp_engine_global), market_name_bytes ) ``` ### Get Perp Engine Global Address ```typescript Typescript theme={null} import { AccountAddress, createObjectAddress } from "@aptos-labs/ts-sdk"; function getPerpEngineGlobalAddress(packageAddress: string): AccountAddress { return createObjectAddress( AccountAddress.fromString(packageAddress), new TextEncoder().encode("GlobalPerpEngine") ); } ``` ```python Python theme={null} from aptos_sdk.account_address import AccountAddress, create_object_address def get_perp_engine_global_address(package_address: str) -> AccountAddress: return create_object_address( AccountAddress.from_str(package_address), "GlobalPerpEngine".encode("utf-8") ) ``` ## Related Build transactions synchronously for better performance Convert decimal values to chain units # Formatting Prices and Sizes for Orders Source: https://docs.decibel.trade/developer-hub/on-chain/overview/formatting-prices-sizes Learn how to convert decimal prices and sizes to chain units using market configuration from the v1/markets endpoint ## Formatting Prices and Sizes for Orders When placing orders on Decibel, you need to convert decimal prices and sizes to chain units that match the market's precision requirements. This guide explains how to use market configuration data from the `v1/markets` endpoint to properly format your order parameters. ## Market Configuration Each market returned from the `v1/markets` endpoint includes precision configuration: ```json theme={null} { "lot_size": 1, "market_addr": "", "market_name": "", "max_leverage": 1, "max_open_interest": 123, "min_size": 1, "px_decimals": 1, "sz_decimals": 1, "tick_size": 1 } ``` ### Market Configuration Fields * **`px_decimals`** - The number of decimal places used for price precision. Prices are stored as integers with this many implied decimal places. For example, if `px_decimals = 9`, a price of `5.67` is stored as `5670000000` (5.67 × 10^9). * **`sz_decimals`** - The number of decimal places used for size precision. Order sizes are stored as integers with this many implied decimal places. For example, if `sz_decimals = 9`, a size of `1.5` is stored as `1500000000` (1.5 × 10^9). * **`tick_size`** - The minimum price increment in chain units. Prices must be multiples of this value. For example, if `tick_size = 1000000` and `px_decimals = 9`, the minimum price increment is `0.001` (1000000 / 10^9). * **`lot_size`** - The minimum size increment in chain units. Order sizes must be multiples of this value. For example, if `lot_size = 100000000` and `sz_decimals = 9`, the minimum size increment is `0.1` (100000000 / 10^9). * **`min_size`** - The minimum order size in chain units. Orders smaller than this will be rejected. For example, if `min_size = 1000000000` and `sz_decimals = 9`, the minimum order size is `1.0` (1000000000 / 10^9). ## Conversion Functions ### Convert Decimal Amount to Chain Units ```typescript Typescript theme={null} /** * Converts a decimal amount to chain units (e.g., USDC). * For USDC, this means multiplying by 10^6. * @param amount - The decimal amount to convert * @param decimal - The number of decimal places for the token (default is 6 for USDC). * @returns The amount in chain units */ export function amountToChainUnits(amount: number, decimal = 6): number { return Math.floor(amount * 10 ** decimal); } ``` ```python Python theme={null} def amount_to_chain_units(amount: float, decimal: int = 6) -> int: """ Converts a decimal amount to chain units (e.g., USDC). For USDC, this means multiplying by 10^6. Args: amount: The decimal amount to convert decimal: The number of decimal places for the token (default is 6 for USDC) Returns: The amount in chain units """ return int(amount * (10 ** decimal)) ``` ### Convert Chain Units to Decimal Amount ```typescript Typescript theme={null} /** * Converts chain units to decimal amount (e.g., USDC). * For USDC, this means dividing by 10^6. * @param chainUnits - The amount in chain units * @param decimal - The number of decimal places for the token (default is 6 for USDC). * @returns The decimal amount */ export function chainUnitsToAmount(chainUnits: number, decimal = 6): number { return chainUnits / 10 ** decimal; } ``` ```python Python theme={null} def chain_units_to_amount(chain_units: int, decimal: int = 6) -> float: """ Converts chain units to decimal amount (e.g., USDC). For USDC, this means dividing by 10^6. Args: chain_units: The amount in chain units decimal: The number of decimal places for the token (default is 6 for USDC) Returns: The decimal amount """ return chain_units / (10 ** decimal) ``` ## Price Formatting ### Round Price to Valid Tick Size Prices must be rounded to the nearest valid tick size. Use this function to ensure your price is valid: ```typescript Typescript theme={null} /** * Rounds a price to the nearest valid tick size * @param price - The decimal price to round * @param market - The market configuration object * @returns The rounded price */ export function roundToValidPrice(price: number, market: PerpMarket): number { if (price === 0) { return 0; } // Convert to chain units const denormalizedPrice = price \* 10 \*\* market.px_decimals; // Round to nearest multiple of tickSize const roundedPrice = Math.round(denormalizedPrice / market.tick_size) \* market.tick_size; // Convert back to decimal const normalizedPrice = Math.round(roundedPrice) / 10 \*\* market.px_decimals; return normalizedPrice; } ``` ```python Python theme={null} def round_to_valid_price(price: float, market: dict) -> float: """ Rounds a price to the nearest valid tick size. Args: price: The decimal price to round market: The market configuration object with px_decimals and tick_size Returns: The rounded price """ if price == 0: return 0.0 # Convert to chain units denormalized_price = price * (10 ** market["px_decimals"]) # Round to nearest multiple of tick_size rounded_price = round(denormalized_price / market["tick_size"]) * market["tick_size"] # Convert back to decimal normalized_price = round(rounded_price) / (10 ** market["px_decimals"]) return normalized_price ``` ## Size Formatting ### Round Size to Valid Lot Size Order sizes must be rounded to the nearest valid lot size and meet the minimum size requirement: ```typescript Typescript theme={null} /** * Rounds an order size to the nearest valid lot size * @param orderSize - The decimal order size to round * @param market - The market configuration object * @returns The rounded order size */ export function roundToValidOrderSize( orderSize: number, market: PerpMarket ): number { if (orderSize === 0) { return 0; } const normalizedMinSize = market.min_size / 10 \*\* market.sz_decimals; // Ensure size meets minimum requirement if (orderSize < normalizedMinSize) { return normalizedMinSize; } // Convert to chain units const denormalizedOrderSize = orderSize \* 10 \*\* market.sz_decimals; // Round to nearest multiple of lotSize const roundedOrderSize = Math.round(denormalizedOrderSize / market.lot_size) \* market.lot_size; // Convert back to decimal const normalizedOrderSize = Math.round(roundedOrderSize) / 10 \*\* market.sz_decimals; return normalizedOrderSize; } ``` ```python Python theme={null} def round_to_valid_order_size(order_size: float, market: dict) -> float: """ Rounds an order size to the nearest valid lot size. Args: order_size: The decimal order size to round market: The market configuration object with sz_decimals, lot_size, and min_size Returns: The rounded order size """ if order_size == 0: return 0.0 normalized_min_size = market["min_size"] / (10 ** market["sz_decimals"]) # Ensure size meets minimum requirement if order_size < normalized_min_size: return normalized_min_size # Convert to chain units denormalized_order_size = order_size * (10 ** market["sz_decimals"]) # Round to nearest multiple of lot_size rounded_order_size = round(denormalized_order_size / market["lot_size"]) * market["lot_size"] # Convert back to decimal normalized_order_size = round(rounded_order_size) / (10 ** market["sz_decimals"]) return normalized_order_size ``` ## Complete Example Here's a complete example of formatting prices and sizes for placing an order: ```typescript Typescript theme={null} // Fetch market data from v1/markets endpoint const market = { market_addr: "0x456...def", market_name: "APT-USD", px_decimals: 9, sz_decimals: 9, tick_size: 1000000, // 0.001 in decimal (1000000 / 10^9) lot_size: 100000000, // 0.1 in decimal (100000000 / 10^9) min_size: 1000000000, // 1.0 in decimal (1000000000 / 10^9) }; // User wants to place an order at $5.6789 with size 1.234 const userPrice = 5.6789; const userSize = 1.234; // Step 1: Round price to valid tick size const roundedPrice = roundToValidPrice(userPrice, market); // Result: 5.679 (rounded to nearest 0.001) // Step 2: Round size to valid lot size and check minimum const roundedSize = roundToValidOrderSize(userSize, market); // Result: 1.2 (rounded to nearest 0.1, meets minimum of 1.0) // Step 3: Convert to chain units for the transaction const chainPrice = amountToChainUnits(roundedPrice, market.px_decimals); // Result: 5679000000 (5.679 × 10^9) const chainSize = amountToChainUnits(roundedSize, market.sz_decimals); // Result: 1200000000 (1.2 × 10^9) // Step 4: Build and submit transaction const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::place_order_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr market.market_addr, // marketAddr chainPrice, // price in chain units chainSize, // size in chain units true, // isBuy 0, // timeInForce false, // isReduceOnly null, // clientOrderId null, // stopPrice null, // tpTriggerPrice null, // tpLimitPrice null, // slTriggerPrice null, // slLimitPrice null, // builderAddress null, // builderFees ], }, }); ``` ```python Python theme={null} # Fetch market data from v1/markets endpoint market = { "market_addr": "0x456...def", "market_name": "APT-USD", "px_decimals": 9, "sz_decimals": 9, "tick_size": 1000000, # 0.001 in decimal (1000000 / 10^9) "lot_size": 100000000, # 0.1 in decimal (100000000 / 10^9) "min_size": 1000000000, # 1.0 in decimal (1000000000 / 10^9) } # User wants to place an order at $5.6789 with size 1.234 user_price = 5.6789 user_size = 1.234 # Step 1: Round price to valid tick size rounded_price = round_to_valid_price(user_price, market) # Result: 5.679 (rounded to nearest 0.001) # Step 2: Round size to valid lot size and check minimum rounded_size = round_to_valid_order_size(user_size, market) # Result: 1.2 (rounded to nearest 0.1, meets minimum of 1.0) # Step 3: Convert to chain units for the transaction chain_price = amount_to_chain_units(rounded_price, market["px_decimals"]) # Result: 5679000000 (5.679 × 10^9) chain_size = amount_to_chain_units(rounded_size, market["sz_decimals"]) # Result: 1200000000 (1.2 × 10^9) # Step 4: Build and submit transaction from aptos_sdk.client import RestClient from aptos_sdk.account import Account PACKAGE = "0x50ead22afd6ffd9769e3b3d6e0e64a2a350d68e8b102c4e72e33d0b8cfdfdb06" rest_client = RestClient("https://fullnode.mainnet.aptoslabs.com") transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::place_order_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr market["market_addr"], # marketAddr chain_price, # price in chain units chain_size, # size in chain units True, # isBuy 0, # timeInForce False, # isReduceOnly None, # clientOrderId None, # stopPrice None, # tpTriggerPrice None, # tpLimitPrice None, # slTriggerPrice None, # slLimitPrice None, # builderAddress None, # builderFees ], }, ) ``` ## Understanding the Values ### Example Market Configuration Let's say a market has the following configuration: ```json theme={null} { "px_decimals": 9, "sz_decimals": 9, "tick_size": 1000000, "lot_size": 100000000, "min_size": 1000000000 } ``` **What this means:** * **Price Precision**: Prices can have up to 9 decimal places. A price of `5.67` is stored as `5670000000` chain units. * **Size Precision**: Sizes can have up to 9 decimal places. A size of `1.5` is stored as `1500000000` chain units. * **Tick Size**: The minimum price increment is `0.001` (1000000 / 10^9). Valid prices are: `5.000`, `5.001`, `5.002`, etc. Invalid: `5.0005`. * **Lot Size**: The minimum size increment is `0.1` (100000000 / 10^9). Valid sizes are: `1.0`, `1.1`, `1.2`, etc. Invalid: `1.05`. * **Min Size**: The minimum order size is `1.0` (1000000000 / 10^9). Orders smaller than 1.0 will be rejected. ## Market-Specific Values For the actual `min_size`, `lot_size`, and `tick_size` values for each live market, see [Market Parameters](/developer-hub/on-chain/overview/market-parameters). ## Common Pitfalls 1. **Not rounding prices**: Prices must be multiples of `tick_size`. Always use `roundToValidPrice()` before converting to chain units. 2. **Not rounding sizes**: Sizes must be multiples of `lot_size`. Always use `roundToValidOrderSize()` before converting to chain units. 3. **Forgetting minimum size**: Orders below `min_size` will be rejected. The rounding function handles this automatically. 4. **Using wrong decimals**: Always use `px_decimals` for prices and `sz_decimals` for sizes when calling `amountToChainUnits()`. # On-Chain Reference Source: https://docs.decibel.trade/developer-hub/on-chain/overview/index Direct transaction reference for building on Decibel without the SDK For developers who need to build transactions directly without using the TypeScript SDK, this section provides complete reference documentation for all on-chain operations. Most developers should use the [TypeScript SDK](/typescript-sdk/overview) instead. The on-chain reference is for advanced use cases or when building in languages without SDK support. **Need the contract addresses?** See [Contract Addresses & Helpers](/developer-hub/on-chain/overview/contract-reference) for package addresses and common helper functions. ## When to Use On-Chain Transactions Building transactions directly (instead of using the SDK) is useful when: * **Language support**: You're building in a language without an official SDK (e.g., Python, Go, Java) * **Low-level control**: You need precise control over transaction construction * **High-frequency trading**: You're optimizing for minimal latency * **Custom integrations**: You're building infrastructure that requires direct blockchain interaction ## Transaction Categories All Decibel transactions are executed on-chain on the Aptos blockchain through Move smart contract function calls. Create Trading Accounts, deposit/withdraw collateral, delegate trading, and manage account settings Place, cancel, and manage trading orders including limit, market, TWAP, and bulk orders Manage take-profit and stop-loss orders for positions Approve and manage builder fees for Trading Accounts Create, fund, and manage trading vaults ## Getting Started You'll need a [Node API token](/quickstart/node-api-key) to submit transactions to the Aptos fullnode, regardless of language. 1. Get the [contract addresses and helper functions](/developer-hub/on-chain/overview/contract-reference) 2. Review [Optimized Transaction Building](/developer-hub/on-chain/overview/optimized-building) for performance best practices 3. Understand [price and size formatting](/developer-hub/on-chain/overview/formatting-prices-sizes) for order parameters 4. Explore the specific transaction type you need # Market Parameters Source: https://docs.decibel.trade/developer-hub/on-chain/overview/market-parameters Min order size, lot size, tick size, and precision for all live Decibel markets Each market has precision parameters that control valid order sizes and prices, returned from `GET /api/v1/markets`. For conversion formulas, see [Formatting Prices and Sizes](/developer-hub/on-chain/overview/formatting-prices-sizes). The generated tables below cover **perp** markets. Spot launches with `APT/USDC` and `BTC/USDC`; for spot precision, call `GET /api/v1/markets` (pass `includeSpot` via `read.markets.getAll({ includeSpot: true })` in the TypeScript SDK) and read each row's `sz_decimals` and `px_decimals`. Spot `sz_decimals` comes from the base asset and `px_decimals` from the quote asset. Generated from the live mainnet perp market configuration on 2026-07-14. Use `GET /api/v1/markets` or `read.markets.getAll()` for the latest runtime values. ## Order Size `human = chain_value / 10^sz_decimals` — sizes must be a multiple of **Lot Size** and at least **Min Size**. | Market | sz\_decimals | Min Size | Lot Size | | ------------ | :----------: | ------------------------- | ------------------------- | | AAPL/USD | 7 | 0.01 AAPL `(100,000)` | 0.001 AAPL `(10,000)` | | AAVE/USD | 7 | 0.01 AAVE `(100,000)` | 0.001 AAVE `(10,000)` | | ADA/USD | 4 | 5 ADA `(50,000)` | 1 ADA `(10,000)` | | AMD/USD | 7 | 0.004 AMD `(40,000)` | 0.001 AMD `(10,000)` | | AMZN/USD | 7 | 0.01 AMZN `(100,000)` | 0.001 AMZN `(10,000)` | | APT/USD | 5 | 1 APT `(100,000)` | 0.1 APT `(10,000)` | | ARM/USD | 7 | 0.005 ARM `(50,000)` | 0.001 ARM `(10,000)` | | ASML/USD | 8 | 0.001 ASML `(100,000)` | 0.0001 ASML `(10,000)` | | AVAX/USD | 6 | 0.2 AVAX `(200,000)` | 0.01 AVAX `(10,000)` | | BABA/USD | 7 | 0.02 BABA `(200,000)` | 0.001 BABA `(10,000)` | | BNB/USD | 7 | 0.002 BNB `(20,000)` | 0.001 BNB `(10,000)` | | BTC/USD | 8 | 0.00002 BTC `(2,000)` | 0.00001 BTC `(1,000)` | | CBRS/USD | 7 | 0.005 CBRS `(50,000)` | 0.001 CBRS `(10,000)` | | CHIP/USD | 3 | 20 CHIP `(20,000)` | 10 CHIP `(10,000)` | | COIN/USD | 7 | 0.01 COIN `(100,000)` | 0.001 COIN `(10,000)` | | COPPER/USD | 5 | 0.2 COPPER `(20,000)` | 0.1 COPPER `(10,000)` | | CRCL/USD | 6 | 0.02 CRCL `(20,000)` | 0.01 CRCL `(10,000)` | | DOGE/USD | 4 | 20 DOGE `(200,000)` | 1 DOGE `(10,000)` | | DRAM/USD | 6 | 0.02 DRAM `(20,000)` | 0.01 DRAM `(10,000)` | | ETH/USD | 8 | 0.0005 ETH `(50,000)` | 0.0001 ETH `(10,000)` | | EWY/USD | 6 | 0.02 EWY `(20,000)` | 0.01 EWY `(10,000)` | | FARTCOIN/USD | 4 | 5 FARTCOIN `(50,000)` | 1 FARTCOIN `(10,000)` | | GOLD/USD | 8 | 0.0005 GOLD `(50,000)` | 0.0001 GOLD `(10,000)` | | GOOGL/USD | 7 | 0.005 GOOGL `(50,000)` | 0.001 GOOGL `(10,000)` | | HOOD/USD | 7 | 0.02 HOOD `(200,000)` | 0.001 HOOD `(10,000)` | | HYPE/USD | 6 | 0.05 HYPE `(50,000)` | 0.01 HYPE `(10,000)` | | IBM/USD | 7 | 0.005 IBM `(50,000)` | 0.001 IBM `(10,000)` | | INTC/USD | 7 | 0.02 INTC `(200,000)` | 0.001 INTC `(10,000)` | | kPEPE/USD | 2 | 500 kPEPE `(50,000)` | 100 kPEPE `(10,000)` | | LINK/USD | 6 | 0.2 LINK `(200,000)` | 0.01 LINK `(10,000)` | | LIT/USD | 4 | 5 LIT `(50,000)` | 1 LIT `(10,000)` | | MEGA/USD | 4 | 10 MEGA `(100,000)` | 1 MEGA `(10,000)` | | META/USD | 7 | 0.004 META `(40,000)` | 0.001 META `(10,000)` | | MRVL/USD | 7 | 0.005 MRVL `(50,000)` | 0.001 MRVL `(10,000)` | | MSFT/USD | 7 | 0.005 MSFT `(50,000)` | 0.001 MSFT `(10,000)` | | MSTR/USD | 7 | 0.01 MSTR `(100,000)` | 0.001 MSTR `(10,000)` | | MU/USD | 7 | 0.002 MU `(20,000)` | 0.001 MU `(10,000)` | | NATGAS/USD | 5 | 0.5 NATGAS `(50,000)` | 0.1 NATGAS `(10,000)` | | NEAR/USD | 5 | 1 NEAR `(100,000)` | 0.1 NEAR `(10,000)` | | NFLX/USD | 6 | 0.02 NFLX `(20,000)` | 0.01 NFLX `(10,000)` | | NVDA/USD | 7 | 0.01 NVDA `(100,000)` | 0.001 NVDA `(10,000)` | | QCOM/USD | 7 | 0.01 QCOM `(100,000)` | 0.001 QCOM `(10,000)` | | QQQ/USD | 7 | 0.004 QQQ `(40,000)` | 0.001 QQQ `(10,000)` | | SAMSUNG/USD | 7 | 0.01 SAMSUNG `(100,000)` | 0.001 SAMSUNG `(10,000)` | | SILVER/USD | 6 | 0.02 SILVER `(20,000)` | 0.01 SILVER `(10,000)` | | SKHYNIX/USD | 8 | 0.001 SKHYNIX `(100,000)` | 0.0001 SKHYNIX `(10,000)` | | SNDK/USD | 8 | 0.001 SNDK `(100,000)` | 0.0001 SNDK `(10,000)` | | SOL/USD | 7 | 0.02 SOL `(200,000)` | 0.001 SOL `(10,000)` | | SPCX/USD | 7 | 0.01 SPCX `(100,000)` | 0.001 SPCX `(10,000)` | | SPY/USD | 7 | 0.004 SPY `(40,000)` | 0.001 SPY `(10,000)` | | SUI/USD | 5 | 1 SUI `(100,000)` | 0.1 SUI `(10,000)` | | TAO/USD | 7 | 0.005 TAO `(50,000)` | 0.001 TAO `(10,000)` | | TRUMP/USD | 5 | 0.4 TRUMP `(40,000)` | 0.1 TRUMP `(10,000)` | | TSLA/USD | 7 | 0.005 TSLA `(50,000)` | 0.001 TSLA `(10,000)` | | WLFI/USD | 4 | 10 WLFI `(100,000)` | 1 WLFI `(10,000)` | | WTIOIL/USD | 6 | 0.02 WTIOIL `(20,000)` | 0.01 WTIOIL `(10,000)` | | XPL/USD | 4 | 10 XPL `(100,000)` | 1 XPL `(10,000)` | | XRP/USD | 5 | 1 XRP `(100,000)` | 0.1 XRP `(10,000)` | | ZEC/USD | 7 | 0.005 ZEC `(50,000)` | 0.001 ZEC `(10,000)` | | ZRO/USD | 5 | 2 ZRO `(200,000)` | 0.1 ZRO `(10,000)` | ## Price `human = chain_value / 10^px_decimals` — prices must be a multiple of **Tick Size**. | Market | Tick Size | | ------------ | ----------------- | | AAPL/USD | \$0.01 `(10,000)` | | AAVE/USD | \$0.01 `(10,000)` | | ADA/USD | \$0.00001 `(10)` | | AMD/USD | \$0.01 `(10,000)` | | AMZN/USD | \$0.01 `(10,000)` | | APT/USD | \$0.0001 `(100)` | | ARM/USD | \$0.01 `(10,000)` | | ASML/USD | \$0.1 `(100,000)` | | AVAX/USD | \$0.001 `(1,000)` | | BABA/USD | \$0.01 `(10,000)` | | BNB/USD | \$0.01 `(10,000)` | | BTC/USD | \$0.1 `(100,000)` | | CBRS/USD | \$0.01 `(10,000)` | | CHIP/USD | \$0.000001 `(1)` | | COIN/USD | \$0.01 `(10,000)` | | COPPER/USD | \$0.0001 `(100)` | | CRCL/USD | \$0.001 `(1,000)` | | DOGE/USD | \$0.00001 `(10)` | | DRAM/USD | \$0.001 `(1,000)` | | ETH/USD | \$0.1 `(100,000)` | | EWY/USD | \$0.001 `(1,000)` | | FARTCOIN/USD | \$0.00001 `(10)` | | GOLD/USD | \$0.1 `(100,000)` | | GOOGL/USD | \$0.01 `(10,000)` | | HOOD/USD | \$0.01 `(10,000)` | | HYPE/USD | \$0.001 `(1,000)` | | IBM/USD | \$0.01 `(10,000)` | | INTC/USD | \$0.01 `(10,000)` | | kPEPE/USD | \$0.000001 `(1)` | | LINK/USD | \$0.001 `(1,000)` | | LIT/USD | \$0.00001 `(10)` | | MEGA/USD | \$0.00001 `(10)` | | META/USD | \$0.01 `(10,000)` | | MRVL/USD | \$0.01 `(10,000)` | | MSFT/USD | \$0.01 `(10,000)` | | MSTR/USD | \$0.01 `(10,000)` | | MU/USD | \$0.01 `(10,000)` | | NATGAS/USD | \$0.0001 `(100)` | | NEAR/USD | \$0.0001 `(100)` | | NFLX/USD | \$0.001 `(1,000)` | | NVDA/USD | \$0.01 `(10,000)` | | QCOM/USD | \$0.01 `(10,000)` | | QQQ/USD | \$0.01 `(10,000)` | | SAMSUNG/USD | \$0.01 `(10,000)` | | SILVER/USD | \$0.001 `(1,000)` | | SKHYNIX/USD | \$0.1 `(100,000)` | | SNDK/USD | \$0.1 `(100,000)` | | SOL/USD | \$0.01 `(10,000)` | | SPCX/USD | \$0.01 `(10,000)` | | SPY/USD | \$0.01 `(10,000)` | | SUI/USD | \$0.0001 `(100)` | | TAO/USD | \$0.01 `(10,000)` | | TRUMP/USD | \$0.0001 `(100)` | | TSLA/USD | \$0.01 `(10,000)` | | WLFI/USD | \$0.00001 `(10)` | | WTIOIL/USD | \$0.001 `(1,000)` | | XPL/USD | \$0.00001 `(10)` | | XRP/USD | \$0.0001 `(100)` | | ZEC/USD | \$0.01 `(10,000)` | | ZRO/USD | \$0.0001 `(100)` | ## Fetching Live Values ```typescript theme={null} import { DecibelReadDex, MAINNET_CONFIG } from "@decibeltrade/sdk"; const read = new DecibelReadDex(MAINNET_CONFIG, { nodeApiKey: process.env.APTOS_NODE_API_KEY!, }); const markets = await read.markets.getAll(); for (const market of markets) { const minSize = market.min_size / 10 ** market.sz_decimals; const lotSize = market.lot_size / 10 ** market.sz_decimals; const tickSize = market.tick_size / 10 ** market.px_decimals; console.log(`${market.market_name}: min=${minSize}, lot=${lotSize}, tick=$${tickSize}`); } ``` # Optimized Transaction Building Source: https://docs.decibel.trade/developer-hub/on-chain/overview/optimized-building For better performance, you can build transactions synchronously using ABI data, a replay protection nonce, and the chain ID. This avoids network calls during transaction construction ## Overview The optimized approach uses: * **ABI (Application Binary Interface)**: Pre-loaded function signatures and parameter types. * **Replay Protection Nonce**: A random 64-bit value embedded in the transaction payload to enable orderless transactions. * **Chain ID**: The network identifier to prevent cross-chain replay attacks. ## Orderless Transactions These transactions are **orderless**, meaning they can be submitted in any order without requiring sequential sequence numbers. The `replayProtectionNonce` is embedded directly in the transaction payload to provide replay protection, eliminating the need to fetch the account's current sequence number from the network. **Benefits of orderless transactions:** * **No sequence number fetch**: Avoids network round-trip to get account sequence number * **Parallel execution**: Multiple transactions can be built and submitted simultaneously * **Better performance**: Faster transaction construction without waiting for network responses * **Improved UX**: Transactions can be prepared offline and submitted later **Traditional (non-orderless) transactions:** * Require fetching the account's current sequence number from the network * Must be submitted sequentially (each transaction increments the sequence number) * Cannot be built in parallel without coordination * Require network calls during transaction construction *** ## Generate Replay Protection Nonce The replay protection nonce is a random 64-bit value that enables orderless transactions. Instead of using the account's sequence number (which requires a network fetch), the nonce is embedded in the transaction payload to prevent replay attacks. **Generate a random 64-bit nonce for replay protection:** ```typescript Typescript theme={null} function generateRandomReplayProtectionNonce(): bigint | null { const buf = new Uint32Array(2); crypto.getRandomValues(buf); const valueAtIndex0 = buf[0]; const valueAtIndex1 = buf[1]; if (!valueAtIndex0 || !valueAtIndex1) return null; // Combine two 32-bit parts into a single 64-bit bigint return (BigInt(valueAtIndex0) << BigInt(32)) | BigInt(valueAtIndex1); } ``` ```python Python theme={null} import secrets def generate_random_replay_protection_nonce() -> int | None: """Generate a random 64-bit nonce for replay protection.""" # Generate 8 random bytes (64 bits) random_bytes = secrets.token_bytes(8) if not random_bytes: return None # Convert bytes to 64-bit integer (big-endian) return int.from_bytes(random_bytes, byteorder="big") ``` *** ## Parse ABI to EntryFunctionABI Before building a transaction, parse the `MoveFunction` ABI to the `EntryFunctionABI` format required for transaction payload construction. ```typescript Typescript theme={null} const parseMoveFnAbiToEntryFnABI = ( functionAbi: MoveFunction ): EntryFunctionABI => { // Remove the signer arguments const numSigners = findFirstNonSignerArg(functionAbi); const params: TypeTag[] = []; for (let i = numSigners; i < functionAbi.params.length; i += 1) { const param = functionAbi.params[i]; if (!param) continue; params.push(parseTypeTag(param, { allowGenerics: true })); } return { signers: numSigners, typeParameters: functionAbi.generic_type_params, parameters: params, }; }; ``` ```python Python theme={null} from aptos_sdk.transactions import EntryFunctionABI from aptos_sdk.type_tag import TypeTag, parse_type_tag def parse_move_fn_abi_to_entry_fn_abi(function_abi: dict) -> EntryFunctionABI: """Parse MoveFunction ABI to EntryFunctionABI format.""" # Count signer arguments (typically "&signer" at the start) num_signers = 0 for param in function_abi.get("params", []): if param and param.startswith("&signer"): num_signers += 1 else: break # Parse non-signer parameters params: list[TypeTag] = [] for i in range(num_signers, len(function_abi.get("params", []))): param = function_abi["params"][i] if not param: continue params.append(parse_type_tag(param, allow_generics=True)) return EntryFunctionABI( signers=num_signers, type_parameters=function_abi.get("generic_type_params", []), parameters=params, ) ``` *** ## Generate Expiration Timestamp A convenience function to compute the expiration timestamp for the transaction. ```typescript Typescript theme={null} const generateExpireTimestamp = (aptosConfig: AptosConfig) => Math.floor(Date.now() / 1000) + aptosConfig.getDefaultTxnExpirySecFromNow(); ``` ```python Python theme={null} import time def generate_expire_timestamp(default_txn_expiry_sec: int = 600) -> int: """Generate expiration timestamp for the transaction.""" return int(time.time()) + default_txn_expiry_sec ``` *** ## Build Transaction Synchronously This function builds a transaction payload and constructs a `RawTransaction` synchronously using all pre-known parameters. ```typescript Typescript theme={null} import { AccountAddress, AccountAddressInput, AptosConfig, ChainId, convertPayloadToInnerPayload, EntryFunctionABI, findFirstNonSignerArg, generateTransactionPayloadWithABI, InputEntryFunctionData, InputEntryFunctionDataWithABI, MoveFunction, parseTypeTag, RawTransaction, SimpleTransaction, TypeTag, } from "@aptos-labs/ts-sdk"; function buildSimpleTransactionSync(args: { aptosConfig: AptosConfig; sender: AccountAddressInput; data: InputEntryFunctionData; chainId: number; gasUnitPrice: number; abi: MoveFunction; withFeePayer: boolean; replayProtectionNonce: bigint; }): SimpleTransaction { const txnPayload = generateTransactionPayloadWithABI({ aptosConfig: args.aptosConfig, function: args.data.function, functionArguments: args.data.functionArguments, typeArguments: args.data.typeArguments, abi: parseMoveFnAbiToEntryFnABI(args.abi), } as InputEntryFunctionDataWithABI); const expireTimestamp = generateExpireTimestamp(args.aptosConfig); const rawTxn = new RawTransaction( AccountAddress.from(args.sender), BigInt("0xdeadbeef"), // Default Sequence Number as it is unused when replay nonce is provided convertPayloadToInnerPayload(txnPayload, args.replayProtectionNonce), // Convert payload and embed replay protection nonce BigInt(args.aptosConfig.getDefaultMaxGasAmount()), BigInt(args.gasUnitPrice), BigInt(expireTimestamp), new ChainId(args.chainId) ); return new SimpleTransaction( rawTxn, args.withFeePayer ? AccountAddress.ZERO : undefined ); } ``` ```python Python theme={null} from aptos_sdk.account import AccountAddress from aptos_sdk.transactions import ( EntryFunction, RawTransaction, TransactionArgument, TransactionPayload, convert_payload_to_inner_payload, ) from aptos_sdk.type_tag import TypeTag, StructTag from aptos_sdk.chain_id import ChainId def build_simple_transaction_sync( sender: AccountAddress, function: str, function_arguments: list, type_arguments: list[TypeTag], abi: dict, chain_id: int, gas_unit_price: int, max_gas_amount: int, expire_timestamp: int, replay_protection_nonce: int, with_fee_payer: bool = False, ) -> RawTransaction: """Build a transaction synchronously using ABI and replay protection nonce.""" # Parse ABI to EntryFunctionABI entry_function_abi = parse_move_fn_abi_to_entry_fn_abi(abi) # Create entry function payload entry_function = EntryFunction( module=StructTag.from_str(function.split("::")[0] + "::" + function.split("::")[1]), function=function.split("::")[2], ty_args=type_arguments, args=[TransactionArgument(arg) for arg in function_arguments], ) payload = TransactionPayload(entry_function) # Convert payload and embed replay protection nonce inner_payload = convert_payload_to_inner_payload(payload, replay_protection_nonce) # Create raw transaction raw_txn = RawTransaction( sender=sender, sequence_number=0xDEADBEEF, # Default sequence number (unused when replay nonce is provided) payload=inner_payload, max_gas_amount=max_gas_amount, gas_unit_price=gas_unit_price, expiration_timestamp_secs=expire_timestamp, chain_id=ChainId(chain_id), ) return raw_txn ``` *** ## Complete Example: Building a Transaction Below is a complete example of building and submitting a transaction using the optimized (orderless, synchronous) approach. ```typescript Typescript theme={null} // Example: Build and submit a transaction synchronously using ABI and replay nonce. import { Aptos, AptosConfig, AccountAddress, SimpleTransaction, MoveFunction, } from "@aptos-labs/ts-sdk"; const subaccountAddr = "0x..."; // Your subaccount address const accountToDelegateTo = "0x..."; // Address to delegate trading to const expirationTimestamp = undefined; // Optional: expiration timestamp in seconds // Initialize Aptos config const aptosConfig = new AptosConfig({ network: "mainnet", fullnode: "https://fullnode.mainnet.aptoslabs.com", }); const aptos = new Aptos(aptosConfig); // ABI for delegate_trading_to function const functionAbi: MoveFunction = { name: "delegate_all_trading_to_for_subaccount", visibility: "friend", is_entry: true, is_view: false, generic_type_params: [], params: ["&signer", "address", "address", "0x1::option::Option"], return: [], }; const replayProtectionNonce = generateRandomReplayProtectionNonce(); // Get gas price (from cache or network) const gasUnitPrice = await aptos .getGasPriceEstimation() .then((r) => r.gas_estimate); // Build transaction synchronously const transaction = buildSimpleTransactionSync({ aptosConfig: aptos.config, sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::delegate_all_trading_to_for_subaccount`, typeArguments: [], functionArguments: [ subaccountAddr, // Subaccount address accountToDelegateTo, // Address to delegate trading to expirationTimestamp, // Optional expiration timestamp (can be undefined) ], }, chainId: 1, // Mainnet chain ID gasUnitPrice, abi: functionAbi, withFeePayer: false, replayProtectionNonce, }); // Sign and submit the transaction const senderAuthenticator = aptos.transaction.sign({ signer: account, transaction, }); const pendingTransaction = await aptos.transaction.submit.simple({ transaction, senderAuthenticator, }); // Wait for transaction confirmation const committedTransaction = await aptos.waitForTransaction({ transactionHash: pendingTransaction.hash, }); console.log("Transaction confirmed:", committedTransaction.hash); ``` ```python Python theme={null} # Example: Build and submit a transaction synchronously using ABI and replay nonce. from aptos_sdk.account import Account, AccountAddress from aptos_sdk.client import RestClient from aptos_sdk.transactions import SignedTransaction from aptos_sdk.type_tag import TypeTag PACKAGE = "0x50ead22afd6ffd9769e3b3d6e0e64a2a350d68e8b102c4e72e33d0b8cfdfdb06" subaccount_addr = "0x..." # Your subaccount address account_to_delegate_to = "0x..." # Address to delegate trading to expiration_timestamp = None # Optional: expiration timestamp in seconds # Initialize Aptos client rest_client = RestClient("https://fullnode.mainnet.aptoslabs.com") # ABI for delegate_trading_to function function_abi = { "name": "delegate_all_trading_to_for_subaccount", "visibility": "friend", "is_entry": True, "is_view": False, "generic_type_params": [], "params": ["&signer", "address", "address", "0x1::option::Option"], "return": [], } # Generate replay protection nonce replay_protection_nonce = generate_random_replay_protection_nonce() # Get gas price (from cache or network) gas_unit_price = rest_client.estimate_gas_price() # Build transaction synchronously transaction = build_simple_transaction_sync( sender=account.address(), function=f"{PACKAGE}::dex_accounts_entry::delegate_all_trading_to_for_subaccount", function_arguments=[ AccountAddress.from_str(subaccount_addr), # Subaccount address AccountAddress.from_str(account_to_delegate_to), # Address to delegate trading to expiration_timestamp, # Optional expiration timestamp (can be None) ], type_arguments=[], abi=function_abi, chain_id=1, # Mainnet chain ID gas_unit_price=gas_unit_price, max_gas_amount=100000, # Default max gas amount expire_timestamp=generate_expire_timestamp(), replay_protection_nonce=replay_protection_nonce, with_fee_payer=False, ) # Sign the transaction signed_transaction = account.sign(transaction) # Submit the transaction pending_transaction = rest_client.submit_transaction(signed_transaction) # Wait for transaction confirmation committed_transaction = rest_client.wait_for_transaction(pending_transaction) print(f"Transaction confirmed: {committed_transaction['hash']}") ``` *** ## Benefits * **Performance**: No network calls during transaction construction * **Reliability**: Deterministic transaction building with pre-loaded ABI * **Security**: Replay protection nonce prevents transaction replay attacks * **Efficiency**: Can build multiple transactions in parallel without blocking *** ## When to Use Use the optimized synchronous approach when: * You have ABI data available locally * You know the chain ID * You want to build transactions without network latency * You're building multiple transactions in batch *** ## Fallback to Async Building If ABI or chain ID is not available, the SDK falls back to async transaction building, which may require a network fetch to get the account's sequence number for replay protection. ```typescript Typescript theme={null} // Fallback: Build a transaction asynchronously when ABI or chainId are missing // This will fetch the account's sequence number from the network. const transaction = await aptos.transaction.build.simple({ sender, data: payload, withFeePayer, options: { replayProtectionNonce, // Still uses nonce if provided, but may also fetch sequence number }, }); ``` ```python Python theme={null} # Fallback: Build a transaction asynchronously when ABI or chainId are missing # This will fetch the account's sequence number from the network. from aptos_sdk.transactions import TransactionBuilder transaction = TransactionBuilder.build_transaction( sender=account.address(), payload=payload, options={ "replay_protection_nonce": replay_protection_nonce, # Still uses nonce if provided, but may also fetch sequence number }, ) ``` **What happens without orderless transactions:** * The SDK makes a network request to fetch the account's current sequence number when you call `aptos.transaction.build.simple()` * The sequence number is used for replay protection instead of (or in addition to) the nonce * Transactions must be submitted sequentially * Each transaction increments the sequence number, preventing parallel submission # Cancel TP/SL Order for Position Source: https://docs.decibel.trade/developer-hub/on-chain/position-management/cancel-tp-sl-order Cancel a take-profit or stop-loss order for a position **Function:** ``` {package}::dex_accounts_entry::cancel_tp_sl_order_for_position ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "cancel_tp_sl_order_for_position", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::perp_market::PerpMarket>", "u128", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `market` - The PerpMarket object * `order_id` - The TP/SL order ID to cancel (u128) **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::cancel_tp_sl_order_for_position`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (PerpMarket object address) 12345678901234567890, // orderId (u128) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::cancel_tp_sl_order_for_position", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (PerpMarket object address) 12345678901234567890, # orderId (u128) ], }, ) ``` # Place TP/SL Order for Position Source: https://docs.decibel.trade/developer-hub/on-chain/position-management/place-tp-sl-order Place take-profit and/or stop-loss orders for an existing position **Function:** ``` {package}::dex_accounts_entry::place_tp_sl_order_for_position ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "place_tp_sl_order_for_position", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<{package}::perp_market::PerpMarket>", "0x1::option::Option", "0x1::option::Option", "0x1::option::Option", "0x1::option::Option", "0x1::option::Option", "0x1::option::Option", "0x1::option::Option
", "0x1::option::Option", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `market` - The PerpMarket object * `tp_trigger_price` - Optional take-profit trigger price `` `>` `` * `tp_limit_price` - Optional take-profit limit price `` `>` `` * `tp_size` - Optional take-profit size `` `>` `` * `sl_trigger_price` - Optional stop-loss trigger price `` `>` `` * `sl_limit_price` - Optional stop-loss limit price `` `>` `` * `sl_size` - Optional stop-loss size `` `>` `` * `builder_address` - Optional builder address `` `>` `` * `builder_fees` - Optional builder fee `` `>` `` **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::place_tp_sl_order_for_position`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (PerpMarket object address) 6000000000, // tpTriggerPrice (optional, 6.0 with 9 decimals) 6050000000, // tpLimitPrice (optional, 6.05 with 9 decimals) 500000000, // tpSize (optional, 0.5 with 9 decimals) 5500000000, // slTriggerPrice (optional, 5.5 with 9 decimals) 5450000000, // slLimitPrice (optional, 5.45 with 9 decimals) 500000000, // slSize (optional, 0.5 with 9 decimals) null, // builderAddress (optional) null, // builderFees (optional) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::place_tp_sl_order_for_position", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (PerpMarket object address) 6000000000, # tpTriggerPrice (optional, 6.0 with 9 decimals) 6050000000, # tpLimitPrice (optional, 6.05 with 9 decimals) 500000000, # tpSize (optional, 0.5 with 9 decimals) 5500000000, # slTriggerPrice (optional, 5.5 with 9 decimals) 5450000000, # slLimitPrice (optional, 5.45 with 9 decimals) 500000000, # slSize (optional, 0.5 with 9 decimals) None, # builderAddress (optional) None, # builderFees (optional) ], }, ) ``` # Update SL Order for Position Source: https://docs.decibel.trade/developer-hub/on-chain/position-management/update-sl-order Update an existing stop-loss order for a position **Function:** ``` {package}::dex_accounts_entry::update_sl_order_for_position ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "update_sl_order_for_position", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "u128", "0x1::object::Object<{package}::perp_market::PerpMarket>", "0x1::option::Option", "0x1::option::Option", "0x1::option::Option", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `order_id` - The SL order ID to update (u128) * `market` - The PerpMarket object * `sl_trigger_price` - Optional new stop-loss trigger price `` `>` `` * `sl_limit_price` - Optional new stop-loss limit price `` `>` `` * `sl_size` - Optional new stop-loss size `` `>` `` **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::update_sl_order_for_position`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr 12345678901234567890, // orderId (u128) "0x456...def", // marketAddr (PerpMarket object address) 5400000000, // slTriggerPrice (optional, 5.4 with 9 decimals) 5350000000, // slLimitPrice (optional, 5.35 with 9 decimals) 750000000, // slSize (optional, 0.75 with 9 decimals) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::update_sl_order_for_position", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr 12345678901234567890, # orderId (u128) "0x456...def", # marketAddr (PerpMarket object address) 5400000000, # slTriggerPrice (optional, 5.4 with 9 decimals) 5350000000, # slLimitPrice (optional, 5.35 with 9 decimals) 750000000, # slSize (optional, 0.75 with 9 decimals) ], }, ) ``` # Update TP Order for Position Source: https://docs.decibel.trade/developer-hub/on-chain/position-management/update-tp-order Update an existing take-profit order for a position **Function:** ``` {package}::dex_accounts_entry::update_tp_order_for_position ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "update_tp_order_for_position", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "u128", "0x1::object::Object<{package}::perp_market::PerpMarket>", "0x1::option::Option", "0x1::option::Option", "0x1::option::Option", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object * `order_id` - The TP order ID to update (u128) * `market` - The PerpMarket object * `tp_trigger_price` - Optional new take-profit trigger price `` `>` `` * `tp_limit_price` - Optional new take-profit limit price `` `>` `` * `tp_size` - Optional new take-profit size `` `>` `` **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::update_tp_order_for_position`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr 12345678901234567890, // orderId (u128) "0x456...def", // marketAddr (PerpMarket object address) 6100000000, // tpTriggerPrice (optional, 6.1 with 9 decimals) 6150000000, // tpLimitPrice (optional, 6.15 with 9 decimals) 750000000, // tpSize (optional, 0.75 with 9 decimals) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::update_tp_order_for_position", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr 12345678901234567890, # orderId (u128) "0x456...def", # marketAddr (PerpMarket object address) 6100000000, # tpTriggerPrice (optional, 6.1 with 9 decimals) 6150000000, # tpLimitPrice (optional, 6.15 with 9 decimals) 750000000, # tpSize (optional, 0.75 with 9 decimals) ], }, ) ``` # Activate Vault Source: https://docs.decibel.trade/developer-hub/on-chain/vault/activate Activate a vault to accept contributions **Function:** ``` {package}::vault_admin_api::activate_vault ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "activate_vault", visibility: "public", is_entry: true, is_view: false, generic_type_params: [], params: ["&signer", "0x1::object::Object<{package}::vault::Vault>"], return: [], }; ``` **Parameters:** * `signer` - The account signer * `vault` - The Vault object **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::vault_admin_api::activate_vault`, typeArguments: [], functionArguments: [ "0xdef...456", // vaultAddr (Vault object address) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::vault_admin_api::activate_vault", "type_arguments": [], "function_arguments": [ "0xdef...456", # vaultAddr (Vault object address) ], }, ) ``` # Contribute to Vault Source: https://docs.decibel.trade/developer-hub/on-chain/vault/contribute Contribute funds to a vault in exchange for shares **Function:** ``` {package}::dex_accounts_entry::contribute_to_vault ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "contribute_to_vault", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "address", "0x1::object::Object<0x1::fungible_asset::Metadata>", "u64", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object used to contribute * `vault` - The vault address * `metadata` - The fungible asset metadata for the contribution asset * `amount` - Contribution amount (u64) **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::contribute_to_vault`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0xdef...456", // vaultAddr (vault address) "0x789...ghi", // metadataAddr (USDC metadata object address) 10000000, // amount (10 USDC with 6 decimals) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::contribute_to_vault", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0xdef...456", # vaultAddr (vault address) "0x789...ghi", # metadataAddr (USDC metadata object address) 10000000, # amount (10 USDC with 6 decimals) ], }, ) ``` # Create and Fund Vault Source: https://docs.decibel.trade/developer-hub/on-chain/vault/create-and-fund Create a new vault with optional initial funding **Function:** ``` {package}::vault_api::create_and_fund_vault ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "create_and_fund_vault", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "0x1::object::Object<0x1::fungible_asset::Metadata>", "0x1::string::String", "0x1::string::String", "vector<0x1::string::String>", "0x1::string::String", "0x1::string::String", "0x1::string::String", "u64", "u64", "u64", "u64", "bool", "bool", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `funded_from_dex_subaccount` - The subaccount used to fund the vault * `contribution_asset_type` - The fungible asset metadata for contributions * `vault_name` - Vault name (String) * `vault_description` - Vault description (String) * `vault_social_links` - Vault social links (vector of Strings). Array format: `[xUrl, discordUrl]` where each element is a string URL or empty string * `vault_share_symbol` - Vault share symbol (String) * `vault_share_icon_uri` - Vault share icon URI (String) * `vault_share_project_uri` - Vault share project URI (String) * `fee_bps` - Fee in basis points (u64). Maximum: 1000 (10%) * `fee_interval_s` - Fee interval in seconds (u64). Minimum: 2,592,000 (30 days). Maximum: 31,536,000 (365 days) * `contribution_lockup_duration_s` - Lockup duration in seconds (u64). Contributors cannot redeem until this period elapses * `initial_funding` - Initial funding amount (u64) * `accepts_contributions` - Whether vault accepts contributions (bool) * `delegate_to_creator` - Whether to delegate to creator (bool) **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::vault_api::create_and_fund_vault`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr (funded_from_dex_subaccount) "0x456...def", // contributionAssetType (USDC metadata object address) "My Trading Vault", // vaultName "A managed vault for algorithmic trading strategies", // vaultDescription ["https://x.com/myvault", "https://discord.gg/myvault"], // vaultSocialLinks (vector: [xUrl, discordUrl]) "MTV", // vaultShareSymbol "https://example.com/icon.png", // vaultShareIconUri "https://example.com/vault", // vaultShareProjectUri 500, // feeBps (500 = 5%, max: 1000 = 10%) 2592000, // feeIntervalS (30 days in seconds, min: 2,592,000, max: 31,536,000) 0, // contributionLockupDurationS (0 = no lockup) 100000000, // initialFunding (100 USDC with 6 decimals) true, // acceptsContributions true, // delegateToCreator ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::vault_api::create_and_fund_vault", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr (funded_from_dex_subaccount) "0x456...def", # contributionAssetType (USDC metadata object address) "My Trading Vault", # vaultName "A managed vault for algorithmic trading strategies", # vaultDescription ["https://x.com/myvault", "https://discord.gg/myvault"], # vaultSocialLinks (vector: [xUrl, discordUrl]) "MTV", # vaultShareSymbol "https://example.com/icon.png", # vaultShareIconUri "https://example.com/vault", # vaultShareProjectUri 500, # feeBps (500 = 5%, max: 1000 = 10%) 2592000, # feeIntervalS (30 days in seconds, min: 2,592,000, max: 31,536,000) 0, # contributionLockupDurationS (0 = no lockup) 100000000, # initialFunding (100 USDC with 6 decimals) True, # acceptsContributions True, # delegateToCreator ], }, ) ``` # Delegate DEX Actions To Source: https://docs.decibel.trade/developer-hub/on-chain/vault/delegate-dex-actions Delegate trading actions to another account for a vault **Function:** ``` {package}::vault_admin_api::delegate_dex_actions_to ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "delegate_dex_actions_to", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::vault::Vault>", "address", "0x1::option::Option", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `vault` - The Vault object * `account_to_delegate_to` - Address to delegate to * `expiration_timestamp_secs` - Optional expiration timestamp `` `>` `` **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::vault_admin_api::delegate_dex_actions_to`, typeArguments: [], functionArguments: [ "0xdef...456", // vaultAddr (Vault object address) "0x789...xyz", // accountToDelegateTo (address to delegate to) 1735689600, // expirationTimestampSecs (optional, Unix timestamp in seconds) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::vault_admin_api::delegate_dex_actions_to", "type_arguments": [], "function_arguments": [ "0xdef...456", # vaultAddr (Vault object address) "0x789...xyz", # accountToDelegateTo (address to delegate to) 1735689600, # expirationTimestampSecs (optional, Unix timestamp in seconds) ], }, ) ``` # Redeem from Vault Source: https://docs.decibel.trade/developer-hub/on-chain/vault/redeem Redeem shares from a vault for underlying assets **Function:** ``` {package}::dex_accounts_entry::redeem_from_vault ``` **ABI Object:** ```typescript theme={null} const functionAbi: MoveFunction = { name: "redeem_from_vault", visibility: "private", is_entry: true, is_view: false, generic_type_params: [], params: [ "&signer", "0x1::object::Object<{package}::dex_accounts::Subaccount>", "address", "u64", ], return: [], }; ``` **Parameters:** * `signer` - The account signer * `subaccount` - The Trading Account object used to redeem * `vault` - The vault address * `shares` - Number of shares to redeem (u64) **Example:** ```typescript Typescript theme={null} const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::redeem_from_vault`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0xdef...456", // vaultAddr (vault address) 500000000, // shares (500 shares with 6 decimals) ], }, }); ``` ```python Python theme={null} transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::redeem_from_vault", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0xdef...456", # vaultAddr (vault address) 500000000, # shares (500 shares with 6 decimals) ], }, ) ``` # Developer Hub Source: https://docs.decibel.trade/developer-hub/overview Build automated trading systems on Decibel **Building with AI tools?** Every page on this site is available as plain Markdown. Append `.md` to any URL, or grab the full site map from [llms.txt](https://docs.decibel.trade/llms.txt). You can also use the contextual menu on any page to copy as Markdown or open directly in Claude, ChatGPT, or Perplexity. ## What is Decibel? Decibel is a decentralized perpetuals exchange with a fully on-chain order book and clearinghouse. Every order is placed, matched, and settled directly on the Aptos blockchain. There's no off-chain matching engine. | | Decibel | Centralized Exchange | | ------------------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | **Builder Codes** | [Permissionlessly earn fees](/quickstart/builder-codes) from trades through your app, service, or bot | Requires broker agreements or affiliate approval | | **Custody** | You hold your keys | Exchange holds your funds | | **Order matching** | On-chain, transparent | Off-chain, opaque | | **Settlement** | On-chain, verifiable | Internal ledger | | **Ecosystem** | Composable with Aptos DeFi | Isolated | Unlike other DEXes that run on app-specific chains, Decibel lives on Aptos, a general-purpose L1. Your assets aren't locked in a bridge or roll-up. You can move them anywhere in the Aptos ecosystem. ## Why Aptos? Decibel needs a blockchain fast enough to run an on-chain order book: * **Parallel execution via Block-STM.** Block times under 20ms. * **Sub-second finality.** Settlement in roughly 0.125 seconds. * **Move VM** for type-safe contracts with formal verification support. * **Global validator set**, not a handful of nodes run by one team. Aptos is one of the few L1s that can deliver the throughput and latency needed for high-frequency trading without off-chain components. For a deeper look at how these pieces fit together - accounts, the orderbook, perps, vaults, and API keys - see [Core Concepts](/quickstart/concepts). ## Choose Your Integration Path Read market data, submit transactions, and manage positions with a typed interface. Direct API access for any language. HTTP for queries, WebSocket for streaming. Build Move modules that interact with Decibel contracts directly. ## Key Concepts for Developers ### Trading Account Model Decibel uses a three-tier account model: Three-tier account model 1. **Login Wallet**: Your main Aptos wallet 2. **API Wallet**: A delegated wallet for signing transactions 3. **Trading Account**: Isolated accounts for margin and positions Each user can have multiple Trading Accounts to isolate strategies. **"Trading Account" = `subaccount` in code.** Throughout the SDK, API, and Move contracts, Trading Accounts are called `subaccount`. The function to create one is `create_new_subaccount`, the SDK method is `createSubaccount`, and the API routes use `/subaccounts`. When you see `subaccount` in code, it means Trading Account. ### Builder Codes Applications can include a Builder Code in transactions to earn a share of trading fees. If you're building a trading interface or bot, [register a Builder Code](/quickstart/builder-codes) to monetize your integration. ### Vault System Vaults are on-chain smart contracts that pool capital under a single manager. Contributors deposit USDC and receive fungible share tokens. Managers trade with pooled funds and earn interval-based performance fees (0–10%, crystallized every 30–365 days). See the [Vault Integration Guide](/developer-hub/guides/vaults) for the full walkthrough. ### Bulk Orders for Market Makers Other decentralized exchanges require you to cancel orders before replacing them. On Decibel, bulk orders are stateful updates. Send your new desired order state and it overwrites the previous one. No cancel transaction. No waiting. This cuts latency for market makers and saves gas. ## Quick Start Place your first order using REST API and WebSocket in under 10 minutes. Create API wallet and get your bearer token ## Architecture Overview Decibel has three main components developers interact with: ### 1. On-Chain Contracts All trading happens on the Aptos blockchain through Move modules. Use the TypeScript SDK's `DecibelWriteDex` to submit transactions. ### 2. REST API The REST API provides read-only access to aggregated data. Good for dashboards, analytics, and low-frequency polling. ### 3. WebSocket API The WebSocket API streams real-time updates. Essential for market making and time-sensitive strategies. ## Guides Programmatic onchain strategy with Vaults: create, fund, activate, and trade on behalf of contributors. Includes TypeScript and Python examples. Efficient order management for market makers Earn fees by routing trades through your application or bot ## On-Chain Reference Detailed documentation for each transaction type: | Category | Description | | ------------------------------------------------------------------------------------ | --------------------------------------------------- | | [Account Management](/developer-hub/on-chain/overview/index) | Create accounts, delegate trading, deposit/withdraw | | [Order Management](/developer-hub/on-chain/order-management/place-order) | Place, cancel, and manage orders | | [Position Management](/developer-hub/on-chain/position-management/place-tp-sl-order) | Take-profit and stop-loss orders | | [Vault Operations](/developer-hub/on-chain/vault/create-and-fund) | Create and manage vaults | ## Support Developer community and support # Auto-Deleveraging (ADL) Source: https://docs.decibel.trade/for-traders/auto-deleveraging Decibel's final circuit breaker for extreme market conditions ADL is the final circuit breaker. It's triggered when the Backstop accumulates irrecoverable losses that threaten protocol solvency. ## When ADL Triggers When ADL triggers: 1. The system identifies the most profitable opposing positions 2. These positions are force-closed at the bankruptcy price (the price at which the Backstop Liquidator would lose exactly the insurance fund amount specified for that market) 3. Total open interest in the market is reduced Closing at bankruptcy price rather than mark price ensures losses are bounded to the insurance fund. ADL is rare and only occurs in extreme scenarios. If your position is closed by ADL, your profit up to the bankruptcy price is realized. ## How Positions Are Selected ADL targets positions based on profitability and leverage. Positions with higher unrealized profit relative to margin used are selected first. This means highly leveraged profitable positions are more likely to be ADL'd than lower-leverage positions with similar profit. ## Related The two-stage liquidation process before ADL How margin requirements work # DLP Vault Source: https://docs.decibel.trade/for-traders/dlp-vault The protocol-owned vault that provides exchange liquidity and serves as the backstop liquidator. Uses the same vault infrastructure as user-created vaults, continuously quoting bid/ask prices across all supported markets. The Decibel Liquidity Provider (DLP) Vault is a protocol-owned [vault](/for-traders/vaults) that solves the chicken-and-egg problem every new exchange faces: you need liquidity to attract traders, but you need traders to attract liquidity. ## The Bootstrap Problem New exchanges face a cold start challenge: * Traders won't come without tight spreads and deep books * Market makers won't provide liquidity without trading volume * Neither side wants to move first The DLP Vault breaks this cycle by providing initial liquidity from day one. ## How It Works The DLP Vault acts as a designated market maker, continuously quoting bid and ask prices across supported markets. It absorbs order flow that would otherwise go unfilled, ensuring traders can always execute at reasonable prices. ### Key Properties * **Protocol-owned.** Not dependent on external market makers staying * **Algorithmic pricing.** Quotes derived from oracle prices with dynamic spreads * **Risk-managed.** Position limits and exposure controls * **Transparent.** All activity visible on-chain ### Backstop Liquidator Role The DLP Vault also serves as a **backstop liquidity provider** in the liquidation waterfall. When a position is liquidated and there isn't enough counterparty liquidity in the orderbook, the DLP steps in to absorb the position — protecting the exchange from bad debt. ## Lockup Period DLP Vault contributions have a **72-hour lockup period**. After contributing, you cannot redeem your shares until 72 hours have passed. This gives the protocol time to deploy your capital effectively and prevents rapid inflows/outflows that could destabilize the market-making strategy. ## Using DLP Shares as Collateral DLP Vault shares are accepted as trading collateral, so you can keep your DLP exposure while trading perps instead of leaving that capital idle. Shares are priced at vault NAV and count toward your account at **90% credit** (a 10% buffer). If your account is liquidated while holding DLP collateral, the shares are redeemed against the vault directly rather than sold on the open market. See [Multi-Collateral](/for-traders/multi-collateral) for the full mechanics. ## Relationship to User Vaults The DLP Vault uses the same vault infrastructure as user-created vaults, but with special parameters: | | DLP Vault | User Vaults | | ----------------------- | ----------------------- | --------------------------------------- | | **Manager** | Protocol (automated) | Any user | | **Strategy** | Automated market making | Manager's discretion | | **Contribution lockup** | 72 hours | 0–7 days (manager-configured) | | **Contributions** | Coming post-mainnet | Available now | | **Fee structure** | 0% | Manager-defined (0–10%, interval-based) | ## Timeline | Phase | Status | | -------------------- | ------------------------------ | | Internal testing | Complete | | Mainnet launch | DLP provides initial liquidity | | Public contributions | Coming post-mainnet | Public contributions to the DLP Vault will open after mainnet launch. Check back for updates on timing and terms. ## Learn More Understanding the vault system and interval-based fees Step-by-step guide to creating and managing your own vault Using DLP shares and other assets as trading collateral # Fees Source: https://docs.decibel.trade/for-traders/fees Trading fees and fee structure on Decibel Trading fees decrease automatically as your 30-day volume grows. Maker fees **drop to zero** at higher tiers, rewarding users who provide liquidity. Perps and spot share **one fee tier**. Your tier comes from a single weighted volume figure that combines both products, so trading spot lowers your perps fees and trading perps lowers your spot fees. ## Weighted 30-Day Volume ``` Weighted 30D Volume = 30D Perps Notional + 4 × 30D Spot Notional ``` Spot notional counts **4x** toward your tier. Spot generates more fees per dollar of notional and carries no leverage, so a dollar of spot volume earns more tier credit than a dollar of perps volume. ## Fee Schedule One tier ladder, two rate sets. Your weighted volume sets the tier, and the tier sets both your perps rates and your spot rates. | Tier | Weighted 30D Volume | Perps (taker / maker) | Spot (taker / maker) | | ---- | ------------------- | --------------------- | -------------------- | | 0 | \< \$1M | 0.045% / 0.015% | 0.070% / 0.040% | | 1 | ≥ \$1M | 0.040% / 0.012% | 0.060% / 0.030% | | 2 | ≥ \$5M | 0.035% / 0.008% | 0.050% / 0.020% | | 3 | ≥ \$25M | 0.030% / 0.004% | 0.040% / 0.010% | | 4 | ≥ \$100M | 0.028% / **0.000%** | 0.035% / **0.000%** | | 5 | ≥ \$250M | 0.026% / **0.000%** | 0.030% / **0.000%** | | 6 | ≥ \$1B | 0.024% / **0.000%** | 0.025% / **0.000%** | For example, \$600K of perps notional and \$150K of spot notional over the last 30 days is a weighted volume of \$600K + 4 × \$150K = \$1.2M, which is tier 1 — 0.040% taker on perps and 0.060% taker on spot. Fee rates and the spot volume weight can be adjusted on-chain. For the rates currently applied to your account, along with your tier and 30-day volume history, call `GET /api/v1/user_fee_rates`. ## Maker vs Taker | Role | Description | | ----- | --------------------------------------------------------- | | Maker | Order adds liquidity to the book (rests before filling) | | Taker | Order removes liquidity from the book (fills immediately) | A limit order that rests on the book before being filled is a maker order. A market order or limit order that fills immediately is a taker order. ### Fee Calculation Fees are calculated as a percentage of the notional value of your trade: ``` Fee = Notional Value × Fee Rate Notional Value = Position Size × Fill Price ``` ### Which Asset Pays the Fee Perps always charge fees in USDC, the collateral asset. Spot charges each side in the asset it receives, deducted from the amount that lands in your account: | Your side | You receive | Fee is charged in | | --------- | ----------- | ----------------- | | Buy | Base asset | Base asset | | Sell | Quote asset | Quote asset | For example, buying BTC in a BTC/USDC spot market means your fee is deducted in BTC. In the API, spot trade rows report this as `fee_asset` alongside `fee_amount`. ## Builder Codes Apps and trading tools can include a Builder Code in transactions to earn a portion of trading fees. If you're using a third-party interface or bot, a Builder Code fee may be included. For details on Builder Codes, see the [Builder Codes guide](/quickstart/builder-codes). ## Funding Fees Funding isn't technically a fee but a payment between traders. Longs pay shorts (or vice versa) based on the funding rate. For details, see [Funding Rates](/for-traders/funding-rates). ## Vault Fees If you contribute to a vault, the vault manager may charge **interval-based performance fees** of 0–10%. Fees are crystallized at the end of each interval (30–365 days, set by the manager at vault creation). The manager only earns fees on intervals where the vault profited — if the vault loses money in an interval, no fees are charged for that period. See [Vaults](/for-traders/vaults) for details. ## Deposit and Withdrawal There are no protocol fees on deposits or withdrawals. You also do not pay network gas. Decibel sponsors the gas on transactions submitted through the app — including deposits, withdrawals, and trades — so you never need to hold APT to move funds or trade. A few wallet types sign and submit their own transactions and therefore pay their own gas, including Petra Vault and some MPC wallets. If you are building your own integration rather than using the Decibel app, see [Gas Station Setup](/quickstart/gas-station) for sponsoring gas for your own users. # Funding Rates Source: https://docs.decibel.trade/for-traders/funding-rates How Decibel funding works at the protocol layer and in the current public product Funding rates keep perpetual prices close to the underlying spot price. When perp trades above spot, longs pay shorts. When perp trades below spot, shorts pay longs. At the protocol layer, Decibel supports two funding modes: * **Continuous funding** when `fundingPeriodS = 0` * **Periodic funding** when `fundingPeriodS > 0` In the current public product, markets are presented with an hourly funding cadence in the UI and API responses. ## Protocol Modes ### Continuous Funding Continuous funding updates the funding state as prices move, without waiting for a fixed settlement window. This is the protocol mode represented by `fundingPeriodS = 0`. ### Periodic Funding Periodic funding uses a configured interval such as 1 hour. Funding still tracks the premium between perp and spot, but realization happens on a defined cadence instead of an every-update basis. ## Current Public Behavior The current public Decibel product uses an hourly funding presentation: * The market header shows a countdown to the next funding boundary * UI APR displays annualize the hourly funding rate * The API exposes `funding_period_s`, so clients can distinguish hourly and continuous modes This page intentionally distinguishes between protocol capability and the current public network presentation. Do not assume every market on every deployment uses the same funding mode. | Exchange | Funding Interval | | ----------------- | ---------------- | | Binance | 8 hours | | dYdX | 8 hours | | HyperLiquid | 1-4 hours | | Decibel public UI | 1 hour | ## How Funding Is Calculated Funding rate has two components: ``` Funding Rate = Premium Index + Interest Rate (clamped) ``` ### Premium Index The premium index measures how far the perp price deviates from the spot (oracle) price. It's calculated using impact bid/ask prices, which represent the price to trade a specific notional amount. When perp > spot: Premium is positive, longs pay shorts When perp \< spot: Premium is negative, shorts pay longs ### Interest Rate The interest rate is a small constant (0.01% per 8 hours) that longs pay shorts when the premium is near zero. This component is clamped within a dead zone (±0.05%) so it doesn't dominate when premium is small. ## When Funding Is Realized Funding affects your position over time and is realized through the protocol's funding mode for that market. In either mode, while your position is open: * Accrued funding appears in your unrealized PnL * It affects your account equity (and liquidation threshold) * You don't pay or receive actual USDC When you reduce or close your position: * Funding is realized proportionally to the size reduction (e.g., closing half your position realizes half the accrued funding) * A full close realizes all accrued funding * Your USDC balance reflects the net amount ## Trader Implications ### For Long-Term Holders If you hold a position through extended periods of high positive funding: * Your unrealized PnL decreases over time * You move closer to liquidation even if price doesn't change * Consider the funding cost as part of your position sizing ### For Short-Term Traders Funding mode changes how you think about timing: * Continuous mode minimizes discrete settlement windows * Periodic mode makes the configured interval visible and easier to monitor in the UI * In both cases, funding should be treated as part of position cost and risk management ### Monitoring Funding Track funding through: * The trading interface shows current rate and accrued amount * API endpoints provide historical rates * WebSocket streams push real-time updates ## Technical Details The system tracks funding through a Cumulative Funding Index (CFI). Each position stores the CFI at entry. Your accrued funding is: ``` Accrued Funding = Position Size × (Current CFI - Entry CFI) ``` The exact update path depends on whether the market is in continuous or periodic mode, but the same index-based accounting model applies: ``` CFI_new = CFI_prev + (Funding_Rate × Oracle_Price × Time_Elapsed) ``` This allows efficient funding calculation without iterating through every position. ## Related How funding affects your equity Why monitoring funding matters for liquidation risk # Liquidations Source: https://docs.decibel.trade/for-traders/liquidations How liquidations work on Decibel and what to expect Liquidation happens when your account equity falls below your maintenance margin requirement. Decibel uses a two-stage liquidation process that's fully transparent and on-chain. ## When Liquidation Triggers Your account becomes eligible for liquidation when: ``` Account Equity < Maintenance Margin Requirement ``` Account equity includes your total collateral plus unrealized PnL (including accrued funding). Maintenance margin is calculated based on your total position notional. ## Two-Stage Process Decibel liquidates positions in two stages, attempting to recover as much value as possible for the trader. ### Stage 1: Market Disposition When your account falls below maintenance margin: 1. The system generates a market order to close your positions 2. The order is bounded by a maximum slippage parameter 3. If equity is restored above maintenance margin, the process ends 4. Any remaining collateral stays in your account Stage 1 tries to close positions through normal market orders. If the orderbook has enough liquidity to fill at reasonable prices, liquidation completes here. ### Stage 2: Backstop Liquidation Backstop Liquidation triggers when Account Equity falls below the backstop maintenance margin (²⁄₃ of MM): 1. The entire account is transferred to the Backstop Liquidator Vault 2. All positions are marked-to-market and PnL is crystallized at current mark price 3. The Backstop absorbs any remaining deficit 4. No socialized losses to other traders The Backstop is a protocol-owned vault that takes over underwater accounts. This ensures that even in extreme market conditions, losses aren't spread across other users. ## Auto-Deleveraging (ADL) Beyond liquidation, Decibel has a final circuit breaker called [Auto-Deleveraging (ADL)](/for-traders/auto-deleveraging). ADL activates in extreme scenarios when the Backstop accumulates irrecoverable losses. It's rare, fully transparent, and ensures protocol solvency without socializing losses. ## Transparent Execution Unlike some exchanges that quietly "turn off" accounts or internalize liquidations, every Decibel liquidation is: * **On-chain.** Verifiable in the transaction history * **Public.** Anyone can see liquidation events * **Async.** Processed on-chain through the liquidation queue, and may span multiple blocks as margin-call orders work down the position * **Non-custodial.** Protocol doesn't hold your funds, just executes rules You can monitor liquidation state through the API and receive alerts before reaching the threshold. ## Avoiding Liquidation To stay above maintenance margin: 1. **Monitor equity.** Watch your account equity relative to MM requirement 2. **Use less leverage.** Lower leverage means more buffer before liquidation 3. **Add collateral.** Deposit more USDC to increase your margin 4. **Reduce positions.** Partially close positions to lower MM requirement 5. **Set stop losses.** Automatically close before reaching liquidation ### Warning Thresholds Consider setting alerts at these levels: | Threshold | Action | | -------------------- | ------------------------------ | | Equity \< 150% of MM | Consider reducing position | | Equity \< 120% of MM | Strong warning, add collateral | | Equity \< 105% of MM | Critical, liquidation imminent | ## Related The final circuit breaker after liquidation How margin requirements are calculated How funding affects your equity # Margin Source: https://docs.decibel.trade/for-traders/margin How cross-margin and leverage work on Decibel Decibel uses cross-margin by default, meaning all your collateral backs all your positions. This page explains how margin, equity, and leverage work together. Collateral can be more than USDC. USDC counts at full value, while accepted secondary assets — such as [DLP Vault](/for-traders/dlp-vault) shares — count toward your account at a collateral credit below 100%. Everywhere this page says "collateral," it means the combined credited value of all your deposited assets. See [Multi-Collateral](/for-traders/multi-collateral) for details. ## Key Concepts ### Account Equity Your account equity is your total value: ``` Account Equity = Total Collateral + Unrealized PnL ``` Unrealized PnL includes both mark-to-market gains/losses and accrued funding. This is the number that determines if you can open new positions or face liquidation. ### Initial Margin (IM) Initial margin is the collateral required to open a position. It's based on the leverage you select: ``` IM Fraction = 1 / User-Selected Leverage ``` For example, if you select 10x leverage, your IM Fraction is 10%. To open a \$10,000 position, you need \$1,000 in initial margin. ### Maintenance Margin (MM) Maintenance margin is the minimum collateral to keep a position open: ``` MM Fraction = 1 / (Max Market Leverage × 2) ``` If the market's max leverage is 40x, the MM Fraction is 1.25%. Your position gets liquidated if your equity falls below your total MM requirement. ## Cross-Margin Behavior With cross-margin, all your collateral is shared across all positions: * Profits from one position cover losses in another * Liquidation only happens when total equity falls below total MM requirement * Capital is more efficient since you don't isolate margin per-position ### Example You have \$10,000 USDC deposited and two positions: * Long BTC-PERP: \$50,000 notional, currently +\$2,000 PnL * Long ETH-PERP: \$30,000 notional, currently -\$1,500 PnL Your account equity is \$10,000 + \$2,000 - \$1,500 = \$10,500. The ETH loss doesn't trigger liquidation because the BTC profit offsets it. ## Isolated Margin Isolated margin allocates collateral to individual positions, limiting your risk to that specific position. If an isolated position gets liquidated, your other positions and remaining collateral are unaffected. You choose cross or isolated **per market**, along with your leverage for that market. Isolated positions hold their own margin, separate from your cross-margin balance: * **Fund an isolated position** by depositing directly to it, or transfer margin between your cross-margin balance and the isolated position at any time. * **Add margin** to an isolated position to move its liquidation price further away; **remove margin** back to cross as long as the position stays above its maintenance requirement. * **Isolated-only markets.** Some markets are configured to trade in isolated mode only. Cross-margin remains the default. Switch a market to isolated from your account settings before opening the position. ## Tradeable and Withdrawable Balance Decibel distinguishes between what you can trade with and what you can withdraw. A PnL haircut (set per market) prevents over-withdrawal on volatile unrealized gains. ### Tradeable Balance Your tradeable balance determines how much you can use to open new positions: ``` Tradeable Balance = Account Equity - max(IM Requirement, PnL Haircut Requirement) ``` The `max()` picks whichever is larger: your initial margin requirement or the PnL haircut. More volatile markets have higher haircut requirements, so large unrealized gains on volatile positions reduce your tradeable balance more than stable ones. ### Withdrawable Balance Your withdrawable balance is more conservative. It's based on collateral value only, excluding unrealized gains: ``` Withdrawable Balance = Account Collateral Value - IM Requirement - Unrealized Loss ``` This means unrealized profits don't increase your withdrawable amount. You can only withdraw collateral that isn't backing open positions or covering unrealized losses. ## Leverage Selection When opening a position, you select your leverage by choosing how much initial margin to allocate. Higher leverage means: * Smaller initial margin requirement * Larger position relative to collateral * Closer to liquidation price * Greater profit/loss per price move | Leverage | IM Fraction | Position Size per \$1,000 | | -------- | ----------- | ------------------------- | | 5x | 20% | \$5,000 | | 10x | 10% | \$10,000 | | 20x | 5% | \$20,000 | | 40x | 2.5% | \$40,000 | ## Key Formulas ``` Account Equity = Total Collateral + Unrealized PnL Unrealized PnL = Mark-to-Market PnL + Unrealized Funding Cost Mark-to-Market PnL = (Current Mark Price - Entry Mark Price) × Position Size IM Requirement = Σ(Position Notional × IM Fraction) MM Requirement = Σ(Position Notional × MM Fraction) Tradeable Balance = Account Equity - max(IM Requirement, PnL Haircut Requirement) Withdrawable Balance = Account Collateral Value - IM Requirement - Unrealized Loss ``` ## Related What happens when equity falls below maintenance margin How funding affects your unrealized PnL # Multi-Collateral Source: https://docs.decibel.trade/for-traders/multi-collateral Use multiple asset types as margin from a single account Decibel supports multiple collateral types from a single cross-margin account. USDC is the primary collateral, and **[DLP Vault](/for-traders/dlp-vault) shares are now accepted as collateral at 90% credit**. Both back all of your positions together — there's no need to convert DLP back to USDC before trading. ## How Collateral Value Is Calculated USDC is the **primary** collateral and always counts at full value. Every other accepted asset is a **secondary** collateral type that counts toward your account at a **collateral credit** below 100%. The credit reflects the asset's liquidity and price volatility — a buffer that protects the exchange if the asset has to be liquidated to cover losses. ``` Collateral Value = USDC Balance + Σ(Secondary Asset Value × Collateral Credit) Secondary Asset Value = Oracle Price × Balance ``` Each secondary asset's value is marked to its oracle price on every account update, so your effective collateral moves with the asset's price. Under the hood, collateral credit is stored as a **haircut** in basis points. A 90% credit is a 10% haircut (1,000 bps) — the two are the same number expressed from opposite ends. ### Accepted Collateral | Asset | Type | Collateral Credit | Notes | | ---------------- | --------- | ----------------- | ------------------------------------------------ | | USDC | Primary | 100% | Settlement asset; PnL and funding settle in USDC | | DLP Vault shares | Secondary | 90% | Priced at vault NAV; see below | Additional secondary assets are under active consideration, and Decibel's collateral framework is built to add them as market conditions and liquidity support it. Each new asset would carry its own collateral credit set by its liquidity and volatility. ## DLP Shares as Collateral If you've contributed to the [DLP Vault](/for-traders/dlp-vault), you can post your vault shares as collateral instead of leaving that capital idle — keeping your DLP exposure while trading perps. * **Priced at NAV.** DLP shares are valued using the vault's net asset value, updated from an on-chain oracle. Your collateral tracks the vault's real-time value. * **90% credit.** Each dollar of DLP (at NAV) contributes \$0.90 of collateral. The 10% buffer absorbs NAV movement between updates and any slippage if shares must be unwound. * **Redeemed on liquidation.** If your account is liquidated while holding DLP collateral, the shares are redeemed against the vault directly (burned) rather than sold on the open market. Because the DLP Vault is itself the backstop liquidity provider, this keeps liquidation self-contained. * **Deposit caps.** A per-asset notional cap can limit how much DLP the system accepts as collateral. If a deposit would push total DLP collateral past the cap, it's rejected. ## Depositing and Withdrawing ### Depositing Deposit USDC or DLP shares directly to your Trading Account — no manual conversion required. DLP begins counting toward your collateral (at 90% credit) as soon as it's deposited, subject to any notional cap. ### Withdrawing You can withdraw secondary collateral as long as your remaining account value still covers your margin requirements. Withdrawals that would drop you below your initial margin — or below the buffer for unrealized losses — are blocked. See [Margin](/for-traders/margin#withdrawable-balance) for how withdrawable balance is computed. ## Cross-Margin All collateral, primary and secondary, is pooled under Decibel's [cross-margin](/for-traders/margin) model. USDC and the credited value of your DLP shares are combined into a single account value that backs every open position. Profits on one position can offset losses on another regardless of which collateral type you deposited. ## What's Next Decibel plans to extend collateral into **borrow-lend based portfolio margining**, letting a broader set of assets serve as margin with risk assessed across your whole portfolio rather than asset by asset. Details and timing will follow — check the [Trader Overview](/for-traders/overview) for the latest. Existing USDC-only accounts continue to work unchanged. Adding DLP collateral is optional — deposit it whenever you want to put idle vault shares to work. ## Related The protocol vault whose shares can be posted as collateral How cross-margin, equity, and withdrawable balance work What happens when equity falls below maintenance margin Contributing to vaults and earning a share of returns # What is Decibel? Source: https://docs.decibel.trade/for-traders/overview A fully on-chain perpetual futures and spot exchange with cross-chain deposits Decibel is a perpetual futures and spot exchange where every order is placed, matched, and settled on-chain. If you have traded perps or spot before, you already know how to use Decibel. ## Get Started 1. **Connect any wallet.** EVM (MetaMask, OKX, Ledger), Solana (Phantom, Solflare), or Aptos (Petra, Aptos Connect). 2. **Deposit USDC.** Click Deposit and select the chain your USDC is on. Decibel bridges it automatically. 3. **Trade.** Perps with up to 50x leverage and cross-margin by default, or spot to hold the asset outright. 4. **Withdraw.** Send USDC back to the chain your wallet is connected to. ## Supported Chains Deposit and withdraw USDC from any of these chains: | Chain | Wallets | | -------- | ------------------------------------------ | | Ethereum | MetaMask, OKX, Ledger, any EIP-1193 wallet | | Arbitrum | Same as Ethereum | | Base | Same as Ethereum | | Solana | Phantom, Solflare, Magic Eden | | Aptos | Petra, Aptos Connect (Google login) | Bridging uses [Wormhole](https://wormhole.com) with Circle's [CCTP](https://www.circle.com/cross-chain-transfer-protocol) for USDC transfers. You do not need to bridge manually. ## Fees Trading fees decrease as your 30-day volume grows, and maker fees drop to zero at higher tiers. Perps and spot share one tier, set by your combined weighted volume (`perps notional + 4 x spot notional`): | Product | Starting taker | Starting maker | Best tier | | ------- | -------------- | -------------- | ------------------------------- | | Perps | 0.045% | 0.015% | 0.024% taker / **0.000%** maker | | Spot | 0.070% | 0.040% | 0.025% taker / **0.000%** maker | Fees are a percentage of notional value (`Position Size x Fill Price`). Perps charge fees in USDC; spot charges each side in the asset it receives. For the full tier ladder, maker/taker definitions, funding fees, and builder code fees, see the [full fee breakdown](/for-traders/fees). No protocol fees on deposits or withdrawals — and Decibel sponsors the network gas, so you never need APT to move funds or trade. ## What Makes Decibel Different? * **Fully on-chain.** The orderbook lives on-chain, not just settlement. Every order, match, and fill is a transaction you can verify. * **Cross-chain deposits.** Connect your existing wallet from Ethereum, Arbitrum, Base, or Solana. No manual bridging. * **Flexible funding modes.** The protocol supports continuous and periodic funding. The current public product presents markets with an hourly funding cadence. * **Builder Codes.** Third-party apps and bots can earn a share of trading fees through [Builder Codes](/quickstart/builder-codes). ## Vaults Not trading directly? Deposit into a vault and let a professional manager trade on your behalf. * **Fungible vault shares.** Your share of the vault is a token you can hold or use elsewhere in DeFi. * **Skin in the game.** Vault managers deposit their own capital alongside contributors. * **Interval-based performance fees.** Managers charge 0-10%, crystallized every 30-365 days. If the vault loses money in an interval, no fees are charged for that period. * **Fully on-chain.** Vault creation, deposits, redemptions, and fee logic all execute as on-chain transactions. Want to run a vault yourself? See the [Vault Launch Guide](/developer-hub/guides/vaults) for developers, or [Vaults](/for-traders/vaults) for how they work as a contributor. ## What Can You Trade? Perpetual futures and spot are both live. More products are on the roadmap. | Product | Status | | ------------------------ | -------------------------------------- | | Perpetual Futures | Live | | Spot Trading | Live (APT/USDC and BTC/USDC at launch) | | Multi-Collateral Support | Live (USDC + DLP shares) | Spot and perp markets for the same asset are separate markets with separate order books — buying BTC on spot does not affect a BTC perp position. See [Perpetuals vs Spot](/for-traders/perps-vs-spot) for how the two differ. For min order sizes, tick sizes, and lot sizes for all live markets, see [Market Parameters](/developer-hub/on-chain/overview/market-parameters). ## Under the Hood Decibel runs natively on Aptos Layer 1. For traders this means fast execution and low gas, but you do not need to know anything about Aptos to use Decibel. Connect your existing wallet, and the cross-chain infrastructure handles the rest. For the technically curious: * **Block-STM parallel execution.** Transactions process in parallel, not sequentially. * **Sub-second finality.** Settlement in roughly 0.125 seconds. * **Move VM.** Smart contracts written in Move, a language designed for safe asset handling. * **No bridges or rollups.** All liquidity lives on a single L1. No fragmentation, no bridge risk. ## Next Steps How perps differ from spot trading Full fee schedule, maker/taker rules, and builder code fees Cross-margin, leverage, and liquidation thresholds Delegating capital to professional vault managers # Perpetuals vs Spot Source: https://docs.decibel.trade/for-traders/perps-vs-spot Understanding the difference between perpetual futures and spot trading Decibel offers both perpetual futures (perps) and spot trading. Both are live, and both run on the same fully on-chain order book. ## What Are Perpetual Futures? Perpetual futures are a contract for difference. You're speculating on whether an asset's price will go up or down, without the actual asset changing hands. ### Key Characteristics * **No expiration.** Unlike traditional futures, perps never expire. * **Leverage.** Trade with more capital than you deposit. * **Long or short.** Profit from both rising and falling prices. * **Cash settlement.** Positions settle in USDC, not the underlying asset. ### Example If you believe BTC will increase in price: 1. Open a long BTC-PERP position with 10x leverage 2. Deposit \$1,000 USDC as collateral 3. Control \$10,000 worth of BTC exposure 4. If BTC rises 5%, your position gains \$500 (50% return on collateral) Leverage amplifies both gains and losses. A 10% adverse move with 10x leverage would result in a 100% loss of your collateral. ## What Is Spot Trading? Spot trading involves actually swapping tokens. When you buy BTC on a spot market, you receive real BTC in your Decibel account. Spot launches with two markets, both quoted in USDC: | Market | Base | Quote | | ---------- | ---- | ----- | | `APT/USDC` | APT | USDC | | `BTC/USDC` | BTC | USDC | ### Key Characteristics * **You own the asset.** A buy settles in the base asset, a sell settles in the quote asset. There is no position to manage and nothing to close. * **Fully collateralized.** Every spot order is backed before it reaches the book: buys escrow the quote asset, sells escrow the base asset. * **No leverage, no funding, no liquidation.** Spot is 1x. There are no funding payments, no margin requirements, and nothing to be liquidated. * **Fees come out of what you receive.** On a buy you pay the fee in the base asset; on a sell you pay it in the quote asset. Perps always charge fees in USDC. See [Fees](/for-traders/fees). ### Order Types Spot supports limit and market orders with `GTC`, `POST_ONLY`, and `IOC` time-in-force. Features that only make sense for positions — take-profit/stop-loss, reduce-only, and TWAP — are perps-only. ### How It Differs from Perps | | Perpetuals | Spot | | ----------------------- | ----------------- | ----------------------------------------------- | | **Asset ownership** | No (cash-settled) | Yes (receive tokens) | | **Leverage** | Yes (up to 50x) | No (1x only) | | **Short selling** | Native support | Not supported — you can only sell what you hold | | **Funding rates** | Yes | No | | **Liquidation risk** | Yes | No | | **What backs an order** | USDC margin | The asset you are giving up, escrowed in full | | **Fees paid in** | USDC | The asset you receive | ## Spot and Perp Markets Are Separate A spot BTC market and a perp BTC market are two different markets with two different market addresses. Buying BTC on spot does not affect a BTC perp position, and the two order books are independent. This matters when you trade programmatically: request the product-specific market address you want, and read each row's `asset_type` (`perp` or `spot`) to tell the two apart. See the [REST API overview](/api-reference/rest/overview#spot-and-perp-coverage) for which endpoints cover which product. ## Which Should You Use? Perpetual futures represent the majority of crypto trading volume. They offer capital efficiency (trade larger positions with less capital), hedging capabilities (protect existing holdings without selling), and price discovery that often leads spot markets. Spot is the better fit when you want to actually hold the asset, or when you want exposure without leverage, funding costs, or liquidation risk. ## Roadmap | Product | Status | Notes | | ----------------- | ------ | -------------------------------------------- | | Perpetual Futures | ✅ Live | Cash-settled, up to 50x leverage | | Spot Trading | ✅ Live | Swap tokens directly — APT and BTC at launch | # Vaults Source: https://docs.decibel.trade/for-traders/vaults Contribute to a trader's vault or launch your own. Managers trade with pooled capital and earn interval-based fees on profits. Decibel vaults let you delegate capital to professional traders while maintaining full transparency and aligned incentives. Unlike copy trading, vaults are on-chain smart contracts with fungible ownership tokens. Decibel also operates the [DLP Vault](/for-traders/dlp-vault), a protocol-owned vault that provides initial exchange liquidity and serves as the backstop liquidator. The mechanics below apply to all vaults, but the DLP Vault has additional responsibilities described on its own page. ## How Vaults Work A vault manager creates a vault, deposits their own capital, and accepts contributions from other users. The manager trades with the pooled capital, and profits (after fees) are distributed proportionally to all vault share holders. ### Key Differentiators | | Decibel Vaults | Copy Trading | | ---------------------- | ------------------------------ | ------------------------------ | | **Ownership** | Fungible tokens (transferable) | Account-level tracking | | **DeFi composability** | Use shares elsewhere | Locked in platform | | **Execution** | Single pool, no cascade | Individual orders per follower | | **Manager incentive** | Capital at risk | Often just fees | | **Fee transparency** | On-chain, verifiable | Opaque | ## Fungible Token Ownership Vault shares are fungible tokens on Aptos. You can: * Transfer shares to another wallet * Use shares as collateral in other DeFi protocols * Trade shares on secondary markets This is fundamentally different from copy trading, where your position is just a number in someone's database. ## Interval-Based Performance Fees Vault managers set their own fee rate within protocol limits. Fees are calculated on an **interval basis** — not using a high watermark. ### How It Works 1. The manager picks a **fee rate** (0–10%) and a **fee interval** (30–365 days) at vault creation. 2. At the end of each interval, the protocol checks if the vault's NAV increased since the interval started. 3. If the vault **profited**, the manager receives their fee percentage as newly minted shares. 4. If the vault **lost money** or broke even, the manager earns nothing for that interval. 5. Each interval resets independently — there is no carry-forward of losses between intervals. ### Vault Parameters | Parameter | Value | | ------------------------- | -------------------------------------- | | **Performance fee range** | 0–10% (set by manager) | | **Fee interval** | 30–365 days | | **Min manager capital** | Lesser of 5% of vault NAV or \$100,000 | | **Min contribution** | \$10 per deposit | | **Min redemption** | \$5 per withdrawal | ## Contribution Lockup Vault managers can configure a **contribution lockup period** of up to 7 days. If a lockup is set, contributors cannot redeem their shares until the lockup period expires after their most recent contribution. This gives the manager time to deploy new capital without immediate redemption pressure. Lockup durations vary by vault — check the vault's details before contributing. ## Manager Capital at Risk Vault managers must deposit and maintain their own capital. The protocol requires the manager to hold at least the lesser of **5% of vault NAV** or **\$100,000**. This aligns incentives: the manager's money is at the same risk as yours. If the vault loses money, the manager loses money too. This is different from copy trading, where the trader you're copying may be running a strategy optimized for other accounts or simply collecting flat fees. ## No Cascade Execution With copy trading, every follower's trade must execute individually. If a popular trader places an order and 1,000 people copy it, that's 1,000 separate transactions hitting the market. This creates: * Slippage as each order moves the market * Latency as orders queue up * Different fill prices for each follower Decibel vaults trade as a single pool. One order, one execution, proportional allocation. No cascade. ## Getting Started Step-by-step guide to creating and managing vaults How to deposit into an existing vault Learn about the protocol-owned liquidity vault Full fee breakdown including vault performance fees # Decibel Documentation Source: https://docs.decibel.trade/index Trader and developer documentation for integrating with Decibel's fully on-chain perpetuals and spot exchange.
# Decibel Documentation

For traders, developers, and architects looking to integrate, use the nav above,

press ⌘I / Ctrl+I for the AI assistant (or ask your question up top in the search bar),

or save time with the quick-start resources below (or just give your AI our llms.txt ).

Trade on behalf of others: create onchain vaults with interval-based performance fees, manage capital, and let depositors earn from your strategy. Place an order, query its status via REST API, and receive real-time updates via WebSocket. Takes about 10 minutes to get your first trade, and then make it your own. Build transactions directly using Move ABIs, with examples in TypeScript and Python. For high-frequency trading, bulk orders, and advanced integrations. Building an app, game, or bot on Decibel? Earn a share of trading fees from your users by using Builder Codes.
Learn more about Decibel
Connect with our community for support and discussion. Try testnet with free funds, or connect any EVM, Solana, or Aptos wallet to trade on mainnet. # Authenticated Requests Source: https://docs.decibel.trade/quickstart/authenticated-requests Learn how to send authenticated requests by signing and submitting on-chain transactions ## Sending Authenticated Requests To place orders and perform trading operations, you need to sign transactions with your private key and broadcast them on-chain. Decibel uses on-chain transactions that are signed with your private key and submitted to the Aptos blockchain. ### Generate an API Key First, generate an API key from the Decibel platform: 1. Visit [https://app.decibel.trade/api](https://app.decibel.trade/api) 2. Connect your wallet 3. Click "Create API Wallet" to generate a new API key 4. Copy and securely store your API key **API Key Security:** Your API key is used to authenticate requests to Decibel's services. Keep it secure and never share it publicly. The API key is used alongside your private key to sign and submit transactions. ### How Authenticated Requests Work Authenticated requests in Decibel follow this general workflow: 1. **Transaction Building**: Build an Aptos transaction calling the appropriate Move function with your parameters 2. **Signing**: Your private key signs the transaction, creating a cryptographic signature 3. **Submission**: The signed transaction is submitted directly to the Aptos blockchain 4. **Confirmation**: Wait for the transaction to be confirmed on-chain and extract relevant information from transaction events **Gas Fees:** By default, you need APT in your account for transaction gas fees. To remove this requirement, set up [Geomi Gas Station](/quickstart/gas-station) to sponsor gas fees on behalf of your users. **Private Key Security:** Never expose your private key in client-side code or commit it to version control. Use environment variables or secure key management systems. Your private key has full control over your account and funds. ### Transaction Documentation For detailed information on how to build and submit specific transactions, see the following documentation: #### Account Management * [Create Trading Account](/developer-hub/on-chain/account-management/create-subaccount) - Create a new Trading Account * [Deposit](/developer-hub/on-chain/account-management/deposit) - Deposit funds to a Trading Account * [Withdraw](/developer-hub/on-chain/account-management/withdraw) - Withdraw funds from a Trading Account * [Delegate Trading](/developer-hub/on-chain/account-management/delegate-trading) - Delegate trading permissions * [Revoke Delegation](/developer-hub/on-chain/account-management/revoke-delegation) - Revoke trading delegation #### Order Management * [Place Order](/developer-hub/on-chain/order-management/place-order) - Place a new order * [Cancel Order](/developer-hub/on-chain/order-management/cancel-order) - Cancel an order by order ID * [Cancel Client Order](/developer-hub/on-chain/order-management/cancel-client-order) - Cancel an order by client order ID * [Place TWAP Order](/developer-hub/on-chain/order-management/place-twap-order) - Place a time-weighted average price order * [Cancel TWAP Order](/developer-hub/on-chain/order-management/cancel-twap-order) - Cancel a TWAP order #### Position Management * [Place TP/SL Order](/developer-hub/on-chain/position-management/place-tp-sl-order) - Place take profit and stop loss orders * [Update TP Order](/developer-hub/on-chain/position-management/update-tp-order) - Update take profit order * [Update SL Order](/developer-hub/on-chain/position-management/update-sl-order) - Update stop loss order * [Cancel TP/SL Order](/developer-hub/on-chain/position-management/cancel-tp-sl-order) - Cancel take profit or stop loss order #### Vault Operations * [Create and Fund Vault](/developer-hub/on-chain/vault/create-and-fund) - Create a new vault and fund it * [Activate Vault](/developer-hub/on-chain/vault/activate) - Activate a vault * [Contribute](/developer-hub/on-chain/vault/contribute) - Contribute funds to a vault * [Redeem](/developer-hub/on-chain/vault/redeem) - Redeem vault shares * [Delegate DEX Actions](/developer-hub/on-chain/vault/delegate-dex-actions) - Delegate vault trading permissions #### Builder Fee * [Approve Max Builder Fee](/developer-hub/on-chain/builder-fee/approve-max-builder-fee) - Approve maximum builder fee * [Revoke Max Builder Fee](/developer-hub/on-chain/builder-fee/revoke-max-builder-fee) - Revoke builder fee approval ### Advanced Topics For more advanced transaction building techniques, see: * [Optimized Transaction Building](/developer-hub/on-chain/overview/optimized-building) - Learn how to build transactions synchronously using ABI data and replay protection nonces for better performance * [Formatting Prices and Sizes](/developer-hub/on-chain/overview/formatting-prices-sizes) - Learn how to format prices and sizes for order-based transactions using market configuration parameters # Builder Codes Source: https://docs.decibel.trade/quickstart/builder-codes Learn about Decibel's technical architecture and how builders can leverage the platform Builder codes allow you to earn fees when users execute transactions through your application. When placing orders or executing other transactions, you can specify a builder address and fee to receive a portion of the transaction fees. **User Approval Required:** Users must approve the maximum builder fee before your application can collect fees. This is a security measure to prevent unauthorized fee collection. Seven projects are already building on Decibel with Builder Codes. Some bring new ways to trade: Copin lets you discover and copy top perp traders, Samosa puts perps in Telegram, and PulseTrader delivers backtested quant signals you can execute in one click. Others extend what's possible: Panora aggregates liquidity across Aptos, RNDM deploys AI agents that run autonomous DeFi strategies, Moar provides up to 15x composable leverage, and Tapp adds programmable hooks to the trading stack. See the [full ecosystem spotlight](https://aptosnetwork.com/currents/decibel-builder-codes-opening-up-the-onchain-trading-engine) for details. ### Step 1: Approve Maximum Builder Fee Before users can pay builder fees, they need to approve a maximum builder fee amount. This is a one-time approval that allows your application to collect fees up to the approved limit: ```typescript theme={null} await dex.approveMaxBuilderFee({ builderAddr: builderAddress, // Builder's address (64 characters, padded with zeros) maxFee: maxBuilderFeeBps, // Maximum fee in basis points (e.g., 10 = 0.1%) }); ``` **Parameters:** * **`builderAddr`**: The address of the builder that should receive the fee. Must be a 64-character hex string (pad with leading zeros after `0x`). * **`maxFee`**: The maximum fee in basis points (1 basis point = 0.01%). For example: * `10` = 0.1% * `100` = 1% * `1000` = 10% ### Step 2: Place Order with Builder Codes Once the builder fee is approved, you can place orders with builder codes: ```typescript theme={null} const orderResult = await dex.placeOrder({ marketName: "APT/USD", price: 300000000, size: 1000000000, isBuy: true, timeInForce: TimeInForce.ImmediateOrCancel, isReduceOnly: false, // Builder code parameters builderAddr: builderAddress, // Same address from Step 1 builderFee: maxBuilderFeeBps, // Must be <= maxFee from Step 1 }); ``` **Builder Code Parameters:** * **`builderAddr`** (optional): The address of the builder that should receive the fee. Must match the address approved in Step 1. * **`builderFee`** (optional): The fee amount in basis points. Must be less than or equal to the `maxFee` approved in Step 1. ### Important Notes * **Approval is required first**: Users must approve the maximum builder fee (Step 1) before you can use builder codes in transactions (Step 2) * **Fee limits**: The `builderFee` in Step 2 cannot exceed the `maxFee` approved in Step 1 * **Address format**: Builder addresses must be 64 characters (pad with leading zeros after `0x`) * **Fee calculation**: Builder fees are added to the user's transaction fees * **Payment**: Builder fees are paid in the same token as the transaction fees * **Optional**: If no builder address is specified, no builder fee is collected ### Example: Placing an Order with Builder Codes Here's the complete flow for using builder codes when placing an order using the TypeScript SDK: ```typescript theme={null} import { DecibelWriteDex, DecibelReadDex, TESTNET_CONFIG, TimeInForce, } from "@decibeltrade/sdk"; import { Ed25519Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk"; // Setup account from private key const privateKeyHex = process.env.PRIVATE_KEY; const user = new Ed25519Account({ privateKey: new Ed25519PrivateKey(privateKeyHex!), }); // Initialize DEX clients const dex = new DecibelWriteDex(TESTNET_CONFIG, user, { skipSimulate: true, }); const readDex = new DecibelReadDex(TESTNET_CONFIG); // Aptos addresses must be 64 characters (pad with leading zeros after 0x) const builderAddress = "0x0000000000000000000000008c967e73e7b15087c42a10d344cff4c96d877f1d"; const maxBuilderFeeBps = 10; // 10 basis points = 0.1% // Step 1: Approve builder fee await dex.approveMaxBuilderFee({ builderAddr: builderAddress, maxFee: maxBuilderFeeBps, }); console.log("\nBuilder fee approved..."); // Step 2: Place a market order with builder fee console.log("\nPlacing order with builder fee..."); const orderResult = await dex.placeOrder({ marketName: "APT/USD", price: 300000000, // 3 USD size: 1000000000, // 1000 APT isBuy: true, timeInForce: TimeInForce.ImmediateOrCancel, // Market order isReduceOnly: false, builderAddr: builderAddress, builderFee: maxBuilderFeeBps, }); if (orderResult.success) { console.log(`Order placed! Transaction: ${orderResult.transactionHash}`); } ``` For more details on builder fees, see the [Builder Fee Transaction Guides](/developer-hub/on-chain/builder-fee/approve-max-builder-fee). ## Resources * [TypeScript SDK Documentation](/typescript-sdk/overview) * [REST API Reference](/api-reference) * [WebSocket API Reference](/api-reference/websocket/overview) * [Transaction Guides](/developer-hub/on-chain/overview/index) * [Builder Fee Guides](/developer-hub/on-chain/builder-fee/approve-max-builder-fee) # Core Concepts Source: https://docs.decibel.trade/quickstart/concepts Mental model for building on Decibel: accounts, orderbook, perps, spot, vaults, and APIs. ## What Decibel Is Decibel is a perpetuals and spot exchange where every order is placed, matched, and settled on the Aptos blockchain. There's no off-chain server deciding who trades with whom. The matching logic is a smart contract that anyone can verify. Three technical pieces make this work: * **An on-chain order book:** a central-limit order book (CLOB) implemented in Move, shared by perp and spot markets. [How it works.](#the-on-chain-orderbook) * **A perp clearinghouse:** the `clearinghouse_perp` module tracks positions, margin, PnL, and liquidations. [How it works.](#perpetuals-and-risk-controls) Spot settles through its own clearinghouse instead, exchanging escrowed assets on each fill with no positions or margin. [More on spot.](#spot-markets) * **Composable DeFi primitives:** orders, positions, vaults, and collateral are all on-chain resources that other apps can build on. [More on vaults.](#vaults) You also need to understand [how accounts work](#accounts-and-trading), [which API keys to use](#api-keys-and-node-access), and [how to integrate](#integrating-with-decibel). ## Accounts and Trading Decibel separates who logs in, who signs trades, and where collateral lives: | Tier | What it is | What it does | | ------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------ | | **Login Wallet** | Your normal Aptos account (e.g. Petra) | Logs into the web app, creates an API Wallet | | **API Wallet** | A dedicated keypair for programmatic trading | Holds APT for gas, signs all on-chain transactions. Create one at `app.decibel.trade/api`. | | **Trading Account** | On-chain object managed by `dex_accounts` | Holds USDC collateral. All orders, PnL, and margin checks route through here. | The typical flow: Login Wallet -> create API Wallet -> create Trading Account -> deposit USDC -> trade. In code, Trading Accounts are called `subaccount`. See [Create Trading Account](/developer-hub/on-chain/account-management/create-subaccount). ## The On-Chain Orderbook Decibel uses a central-limit order book (CLOB) implemented in Move: * The order book, matching engine, and clearinghouse work together to: * Check margin and risk. * Route between maker/taker, TWAP, and bulk orders. * Execute via [Block-STM](https://aptos.dev/network/blockchain/execution#block-stm), so matching and settlement happen in one Aptos transaction. Three properties to know: * **Price-time priority:** Bids and asks are sorted by `(price, unique_idx)`, so the best-priced, earliest order matches first. * **Deterministic fairness:** No off-chain relay can jump the queue. Matching logic is part of the chain. * **Atomic settlement:** Matching and PnL/collateral updates commit (or abort) in the same transaction. ## Perpetuals and Risk Controls Perp contracts live in `clearinghouse_perp.move` and related modules: * **Mark price:** Median of the oracle price, orderbook mid price, and a basis-adjusted price: `median(P_oracle, P_mid, P_basis)` where `P_basis = P_oracle * EMA_150s(P_mid / P_oracle)`. Used for PnL and margin checks. * **Funding modes:** The protocol supports continuous (`fundingPeriodS = 0`) and periodic (`fundingPeriodS > 0`) funding. Current public markets are presented with an hourly cadence. See [Funding Rates](/for-traders/funding-rates). ### Margin Cross margin uses one collateral pool to back all positions. Isolated margin locks collateral per-position. See [Margin](/for-traders/margin) for full details. ### Global Risk Controls * **Price bands:** Settlement must stay within a governance-set band around the mark price. * **Circuit breakers:** Can pause matching/withdrawals on extreme oracle deviations. * **ADL (auto-deleveraging):** Last-resort mechanism to protect solvency if insurance funds are exhausted. ## Spot Markets Spot contracts live in `spot_clearinghouse.move` and `spot_engine.move`. A spot market trades a base asset against a quote asset on the same CLOB the perps use, but it settles assets instead of tracking positions: * **Per-order escrow:** Every order is fully collateralized before it enters the book. Buys escrow the quote asset, sells escrow the base asset. * **Immediate settlement:** Each fill exchanges the escrowed assets in the same transaction. There is no position, no margin, and nothing to liquidate. * **Fees in the received asset:** Protocol and builder fees are deducted from what each side receives — base on a buy, quote on a sell — rather than from USDC collateral. See [Fees](/for-traders/fees#which-asset-pays-the-fee). Because spot has no positions, it also has no mark price, oracle price, funding, or open interest. Spot display prices come from the book itself: `GET /api/v1/spot/asset_contexts`, `GET /api/v1/orderbook`, or the `all_spot_mids` and `depth:{marketAddr}` WebSocket topics. Spot and perp markets for the same asset are **separate markets with separate addresses**. Endpoints that return both products tag each row with `asset_type` (`perp` or `spot`); see the [REST API overview](/api-reference/rest/overview#spot-and-perp-coverage) for per-endpoint coverage. To place spot orders on-chain, see [Place Spot Order](/developer-hub/on-chain/order-management/place-spot-order). ## Vaults Vaults let you run on-chain strategies that others can deposit into: * A vault is a Move resource that: * Holds collateral (e.g. USDC). * Mints fungible vault shares (a claim on assets). * Charges interval-based performance fees (0–10%, crystallized every 30–365 days) in shares. * Depositors contribute USDC and receive shares at the current share price. * Managers trade via delegated permissions; fees are crystallized periodically as additional shares. Two types of vaults: * **Protocol vault:** Managed by Decibel, has a 72-hour lockup and stricter risk settings. * **User vaults:** Created and managed by any user; deposits are withdrawable without protocol lockups by default. Vault shares are fungible tokens on Aptos, so you can trade them or compose them in other DeFi protocols. See [Vaults for Traders](/for-traders/vaults) for contributor details, the [Vault Integration Guide](/developer-hub/guides/vaults) for the full developer walkthrough, or [Vault Transactions](/developer-hub/on-chain/vault/create-and-fund) for the underlying Move entry functions. ## API Keys and Node Access You'll see three different "keys" in the docs: | Key | Purpose | How it's used | | ------------------------------------------------------------ | ------------------------------------------------------------ | -------------------------------------------------------------- | | **Client API key** ([Geomi](https://geomi.dev/)) | GET endpoints on `https://api.mainnet.aptoslabs.com/decibel` | Sent as `Authorization: Bearer ` | | **Node API key** ([Geomi](https://geomi.dev/) / Aptos Build) | SDK connection to Aptos fullnodes | Passed as `nodeApiKey` to `DecibelReadDex` / `DecibelWriteDex` | | **API Wallet private key** | Signs on-chain transactions | Never commit to Git; store in `.env` or a secrets manager | **Rule of thumb:** Reading data needs a Client API key + Node API key. Sending transactions needs a Node API key + API Wallet private key. ## Integrating with Decibel There are three layers for interacting with Decibel, each with different read/write access: | Layer | Access | What it does | | ---------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | | **TypeScript SDK** (`@decibeltrade/sdk`) | Read + Write | Handles ABI, replay protection, gas, and JSON decoding. High-level helpers like `placeOrder`, `placeTwapOrder`, `depositToVault`. | | **REST & WebSocket APIs** | Read | REST for queries (`GET /api/v1/markets`, `/orders`, `/positions`). WebSocket for streaming prices, depth, trades. | | **Raw Aptos transactions** | Write | Call Move entry functions directly (e.g. `dex_accounts_entry::place_order_to_subaccount`). Full control over payloads, ABI parsing, and signing. | ## Next Steps Set up credentials and place your first trade in under 5 minutes Move entry function signatures and examples for every transaction type Create and manage onchain vaults with pooled capital and performance fees # Market Data Source: https://docs.decibel.trade/quickstart/market-data Learn how to send unauthenticated requests to access public market data ## Base URLs Decibel API supports two environments: **Mainnet:** ``` https://api.mainnet.aptoslabs.com/decibel ``` **Testnet:** ``` https://api.testnet.aptoslabs.com/decibel ``` **Note about the API URL:** The base URLs provide access to all Decibel markets and trading functionality. This includes perpetual futures markets, spot markets, and more. ## Package Addresses Each environment has its own package address: **Mainnet Package Address:** ``` 0x50ead22afd6ffd9769e3b3d6e0e64a2a350d68e8b102c4e72e33d0b8cfdfdb06 ``` **Testnet Package Address:** ``` 0xe7da2794b1d8af76532ed95f38bfdf1136abfd8ea3a240189971988a83101b7f ``` **No authentication required:** The endpoints in this guide are public and don't require authentication headers like OAuth or JWT. However, you **do** still need a Decibel **Node API key** to access the node; simply pass it as the `Authorization` header on your requests, in the format:\ `Authorization: Bearer ` **Base URL Variable:** In the code examples below, `BASE_URL` refers to either: - `https://api.mainnet.aptoslabs.com/decibel` for Mainnet - `https://api.testnet.aptoslabs.com/decibel` for Testnet Make sure to set this variable in your code before making requests. ## Step 1: Get Available Markets Let's start by fetching the list of available markets. We'll use the Get Markets endpoint to retrieve all active trading markets. ```python Python theme={null} import requests BASE_URL = "https://api.mainnet.aptoslabs.com/decibel" NODE_API_KEY = "YOUR_NODE_API_KEY" headers = {"Authorization": f"Bearer {NODE_API_KEY}"} # Make a GET request to the markets endpoint response = requests.get(f"{BASE_URL}/api/v1/markets", headers=headers) # Check if the request was successful if response.status_code == 200: markets = response.json() print(f"Found {len(markets)} markets") # Print first 5 markets for market in markets[:5]: print(f"- {market.get('market_name', 'N/A')} (leverage: {market.get('max_leverage', 'N/A')}x, addr: {market.get('market_addr', 'N/A')})") else: print(f"Error: {response.status_code}") print(response.text) ``` ```typescript TypeScript theme={null} const BASE_URL = "https://api.mainnet.aptoslabs.com/decibel"; const NODE_API_KEY = "YOUR_NODE_API_KEY"; fetch(`${BASE_URL}/api/v1/markets`, { headers: { Authorization: `Bearer ${NODE_API_KEY}`, }, }) .then((response) => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then((markets) => { console.log(`Found ${markets.length} markets`); markets.slice(0, 5).forEach((market) => { console.log(`- ${market.market_name || "N/A"} (leverage: ${market.max_leverage || "N/A"}x, addr: ${market.market_addr || "N/A"})`); }); }) .catch((error) => { console.error("Error:", error); }); ``` ```bash cURL theme={null} # Mainnet curl -X GET https://api.mainnet.aptoslabs.com/decibel/api/v1/markets \ -H "Authorization: Bearer YOUR_NODE_API_KEY" # Testnet curl -X GET https://api.testnet.aptoslabs.com/decibel/api/v1/markets \ -H "Authorization: Bearer YOUR_NODE_API_KEY" ``` ## Step 2: Get Perp Market Prices After obtaining the list of markets, you can query perp price information for a specific market - including oracle price, mark price, mid price, funding rate, and open interest - using its market address. Spot markets do not publish `/prices` rows. For spot display prices, use `/api/v1/spot/asset_contexts` or the `all_spot_mids` WebSocket topic. For one market's live book mid, use `/api/v1/orderbook` or `depth:{marketAddr}` and derive mid price from best bid and best ask. ```python Python theme={null} import requests BASE_URL = "https://api.mainnet.aptoslabs.com/decibel" NODE_API_KEY = "YOUR_NODE_API_KEY" headers = {"Authorization": f"Bearer {NODE_API_KEY}"} # Replace 'market_address' with an actual market address from Step 1 # Example: "BTC/USD: 0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861" market_address = "0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861" # Get market details response = requests.get(f"{BASE_URL}/api/v1/prices?market={market_address}", headers=headers) if response.status_code == 200: data = response.json() if data: market = data[0] print(f"Market: {market.get('market', 'N/A')}") print(f"Oracle Price: {market.get('oracle_px', 'N/A')}") print(f"Mark Price: {market.get('mark_px', 'N/A')}") print(f"Mid Price: {market.get('mid_px', 'N/A')}") print(f"Funding Rate (bps): {market.get('funding_rate_bps', 'N/A')}") print(f"Open Interest: {market.get('open_interest', 'N/A')}") else: print("No data returned") else: print(f"Error: {response.status_code}") print(response.text) ``` ```typescript TypeScript theme={null} const BASE_URL = "https://api.mainnet.aptoslabs.com/decibel"; const NODE_API_KEY = "YOUR_NODE_API_KEY"; const marketAddress = "0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861"; fetch(`${BASE_URL}/api/v1/prices?market=${marketAddress}`, { headers: { Authorization: `Bearer ${NODE_API_KEY}`, }, }) .then((response) => response.json()) .then((data) => { if (data && data.length > 0) { const market = data[0]; console.log(`Market: ${market.market || "N/A"}`); console.log(`Oracle Price: ${market.oracle_px || "N/A"}`); console.log(`Mark Price: ${market.mark_px || "N/A"}`); console.log(`Mid Price: ${market.mid_px || "N/A"}`); console.log(`Funding Rate (bps): ${market.funding_rate_bps || "N/A"}`); console.log(`Open Interest: ${market.open_interest || "N/A"}`); } else { console.log("No data returned"); } }) .catch((error) => { console.error("Error:", error); }); ``` ```bash cURL theme={null} # Mainnet curl -X GET "https://api.mainnet.aptoslabs.com/decibel/api/v1/prices?market=0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861" \ -H "Authorization: Bearer YOUR_NODE_API_KEY" # Testnet curl -X GET "https://api.testnet.aptoslabs.com/decibel/api/v1/prices?market=0x161b7b3f58327d057ee5824de0c1a4fc4fa3d121b847c138e921a255768a0dca" \ -H "Authorization: Bearer YOUR_NODE_API_KEY" ``` ## Step 3: Get Order Book Data Now let's retrieve the order book for one market, which shows the current buy and sell orders with their prices and sizes. Pass a market address returned by `/api/v1/markets`. The same endpoint supports perp and spot market addresses, but each request resolves to one concrete market only. A BTC perp market and a BTC spot market are different markets with different addresses, so request the exact product-specific market address you want. ```python Python theme={null} import requests BASE_URL = "https://api.mainnet.aptoslabs.com/decibel" NODE_API_KEY = "YOUR_NODE_API_KEY" headers = {"Authorization": f"Bearer {NODE_API_KEY}"} # Replace with a market address from Step 1 market_address = "0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861" # Get order book response = requests.get( f"{BASE_URL}/api/v1/orderbook", params={"market": market_address}, headers=headers, ) if response.status_code == 200: orderbook = response.json() print("Bids (Buy Orders):") for bid in orderbook.get("bids", [])[:5]: print(f" Price: {bid[0]}, Size: {bid[1]}") print("\nAsks (Sell Orders):") for ask in orderbook.get("asks", [])[:5]: print(f" Price: {ask[0]}, Size: {ask[1]}") else: print(f"Error: {response.status_code}") ``` ```typescript TypeScript theme={null} const BASE_URL = "https://api.mainnet.aptoslabs.com/decibel"; const NODE_API_KEY = "YOUR_NODE_API_KEY"; const marketAddress = "0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861"; fetch(`${BASE_URL}/api/v1/orderbook?market=${marketAddress}`, { headers: { Authorization: `Bearer ${NODE_API_KEY}`, }, }) .then((response) => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then((orderbook) => { console.log("Bids (Buy Orders):"); orderbook.bids.slice(0, 5).forEach((bid: [string, string]) => { console.log(` Price: ${bid[0]}, Size: ${bid[1]}`); }); console.log("\nAsks (Sell Orders):"); orderbook.asks.slice(0, 5).forEach((ask: [string, string]) => { console.log(` Price: ${ask[0]}, Size: ${ask[1]}`); }); }) .catch((error) => { console.error("Error:", error); }); ``` ```bash cURL theme={null} # Mainnet curl -X GET "https://api.mainnet.aptoslabs.com/decibel/api/v1/orderbook?market=0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861" \ -H "Authorization: Bearer YOUR_NODE_API_KEY" # Testnet curl -X GET "https://api.testnet.aptoslabs.com/decibel/api/v1/orderbook?market=0x161b7b3f58327d057ee5824de0c1a4fc4fa3d121b847c138e921a255768a0dca" \ -H "Authorization: Bearer YOUR_NODE_API_KEY" ``` ## Step 4: Get Recent Trades Finally, let's fetch recent trades for one market address to see the latest trading activity. HTTP `/api/v1/trades` supports both perp and spot market addresses, but each request is still for one concrete market only. A spot BTC market and a perp BTC market have different addresses and are never combined. Spot rows are returned from the taker's perspective; user-specific spot fills are available from `/api/v1/trade_history`. ```python Python theme={null} import requests BASE_URL = "https://api.mainnet.aptoslabs.com/decibel" NODE_API_KEY = "YOUR_NODE_API_KEY" headers = {"Authorization": f"Bearer {NODE_API_KEY}"} # Replace 'market_address' with an actual market address from Step 1 # Example: "BTC/USD: 0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861" market_address = "0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861" # Get recent trades response = requests.get( f"{BASE_URL}/api/v1/trades", params={"market": market_address, "limit": 20, "offset": 0}, headers=headers, ) if response.status_code == 200: data = response.json() trades = data.get("items", []) total_count = data.get("total_count", 0) print(f"Recent Trades (Total: {total_count}):") for trade in trades[:10]: print( f" Type: {trade.get('asset_type')}, Action: {trade.get('action')}, " f"Price: {trade.get('price')}, Size: {trade.get('size')}, " f"Fee: {trade.get('fee_amount')} {trade.get('fee_asset') or ''}" ) else: print(f"Error: {response.status_code}") print(response.text) ``` ```typescript TypeScript theme={null} const BASE_URL = "https://api.mainnet.aptoslabs.com/decibel"; const NODE_API_KEY = "YOUR_NODE_API_KEY"; const marketAddress = "0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861"; fetch(`${BASE_URL}/api/v1/trades?market=${marketAddress}&limit=20&offset=0`, { headers: { Authorization: `Bearer ${NODE_API_KEY}`, }, }) .then((response) => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then((data) => { const trades = data.items || []; const totalCount = data.total_count || 0; console.log(`Recent Trades (Total: ${totalCount}):`); trades.slice(0, 10).forEach((trade: any) => { console.log( ` Type: ${trade.asset_type}, Action: ${trade.action}, ` + `Price: ${trade.price}, Size: ${trade.size}, ` + `Fee: ${trade.fee_amount} ${trade.fee_asset || ""}`, ); }); }) .catch((error) => { console.error("Error:", error); }); ``` ```bash cURL theme={null} # Mainnet curl -X GET "https://api.mainnet.aptoslabs.com/decibel/api/v1/trades?market=0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861&limit=20&offset=0" \ -H "Authorization: Bearer YOUR_NODE_API_KEY" # Testnet curl -X GET "https://api.testnet.aptoslabs.com/decibel/api/v1/trades?market=0x161b7b3f58327d057ee5824de0c1a4fc4fa3d121b847c138e921a255768a0dca&limit=20&offset=0" \ -H "Authorization: Bearer YOUR_NODE_API_KEY" ``` ## Step 5: Get User Fee Rates Query a user's current maker/taker fee rates, fee tier based on 30-day rolling volume, the full VIP fee schedule, and daily volume history. Fee-rate and discount fields are returned as decimal numbers (not strings). ```python Python theme={null} import requests BASE_URL = "https://api.mainnet.aptoslabs.com/decibel" NODE_API_KEY = "YOUR_NODE_API_KEY" headers = {"Authorization": f"Bearer {NODE_API_KEY}"} account = "0xYOUR_ACCOUNT_ADDRESS" response = requests.get(f"{BASE_URL}/api/v1/user_fee_rates?account={account}", headers=headers) if response.status_code == 200: data = response.json() print(f"Account: {data['account']}") print(f"Fee Tier: {data['fee_tier']}") print(f"Taker Rate: {data['user_taker_rate']}") print(f"Maker Rate: {data['user_maker_rate']}") print(f"Active Referral Discount: {data['active_referral_discount']}") print(f"30-day daily volume entries: {len(data['daily_user_volume'])}") print("\nVIP Fee Schedule:") for tier in data['fee_schedule']['tiers']['vip']: print(f" >= ${int(tier['volume_threshold']):,} USD -> taker {tier['taker']}, maker {tier['maker']}") else: print(f"Error: {response.status_code}") print(response.text) ``` ```typescript TypeScript theme={null} const BASE_URL = "https://api.mainnet.aptoslabs.com/decibel"; const NODE_API_KEY = "YOUR_NODE_API_KEY"; const account = "0xYOUR_ACCOUNT_ADDRESS"; fetch(`${BASE_URL}/api/v1/user_fee_rates?account=${account}`, { headers: { Authorization: `Bearer ${NODE_API_KEY}`, }, }) .then((response) => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then((data) => { console.log(`Account: ${data.account}`); console.log(`Fee Tier: ${data.fee_tier}`); console.log(`Taker Rate: ${data.user_taker_rate}`); console.log(`Maker Rate: ${data.user_maker_rate}`); console.log(`Active Referral Discount: ${data.active_referral_discount}`); console.log(`30-day daily volume entries: ${data.daily_user_volume.length}`); console.log("\nVIP Fee Schedule:"); data.fee_schedule.tiers.vip.forEach( (tier: { volume_threshold: string; taker: number; maker: number }) => { console.log( ` >= $${Number(tier.volume_threshold).toLocaleString()} USD -> taker ${tier.taker}, maker ${tier.maker}`, ); }, ); }) .catch((error) => { console.error("Error:", error); }); ``` ```bash cURL theme={null} # Mainnet curl -X GET "https://api.mainnet.aptoslabs.com/decibel/api/v1/user_fee_rates?account=0xYOUR_ACCOUNT_ADDRESS" \ -H "Authorization: Bearer YOUR_NODE_API_KEY" # Testnet curl -X GET "https://api.testnet.aptoslabs.com/decibel/api/v1/user_fee_rates?account=0xYOUR_ACCOUNT_ADDRESS" \ -H "Authorization: Bearer YOUR_NODE_API_KEY" ``` # Client API Key Setup Source: https://docs.decibel.trade/quickstart/node-api-key Learn how to set up a Client API key from Geomi to access Decibel's GET APIs ## Client API Key Overview Decibel's GET APIs require a **Client API Key** for authentication. Without a valid Client API key, GET API requests will fail. The Client API key is used to authenticate requests to Decibel's read-only endpoints. **Required for GET APIs:** All GET API requests require a Client API key. Requests without a valid Client API key will be rejected. ## Getting a Client API Key To obtain a Client API key, you need to create one on Geomi: 1. Visit [https://geomi.dev](https://geomi.dev) 2. Sign up or log in to your account 3. Navigate to the client keys section 4. Generate a new client API key 5. Copy and securely store your Client API key **Geomi Account:** You'll need a Geomi account to generate Client API keys. If you don't have one, you can sign up at [https://geomi.dev](https://geomi.dev). ## Using the Client API Key Once you have your Client API key, include it in the `Authorization` header of your HTTP requests: ```bash theme={null} Authorization: Bearer YOUR_CLIENT_API_KEY ``` ### Example Requests Here are examples of making a GET request with the Client API key in different languages: ```bash curl theme={null} curl -X GET "https://api.mainnet.aptoslabs.com/decibel/api/v1/markets" \ -H "Authorization: Bearer YOUR_CLIENT_API_KEY" ``` ```typescript TypeScript theme={null} const response = await fetch("https://api.mainnet.aptoslabs.com/decibel/api/v1/markets", { headers: { Authorization: `Bearer ${CLIENT_API_KEY}`, }, }); const data = await response.json(); ``` ```python Python theme={null} import requests headers = { "Authorization": f"Bearer {CLIENT_API_KEY}" } response = requests.get( "https://api.mainnet.aptoslabs.com/decibel/api/v1/markets", headers=headers ) data = response.json() ``` **Security Best Practices:** - Never commit your Client API key to version control - Store API keys in environment variables or secure key management systems - Rotate your API keys regularly - Use different keys for development and production environments ## Troubleshooting ### 401 Unauthorized Error If you receive a `401 Unauthorized` error: 1. Verify your Client API key is correct 2. Ensure you're using the `Bearer` token format: `Authorization: Bearer YOUR_KEY` 3. Confirm your key hasn't expired or been revoked on Geomi ### 403 Forbidden Error If you receive a `403 Forbidden` error: 1. Verify your Client API key is correct 2. Check that your key has the necessary permissions 3. Ensure the key is properly formatted in the Authorization header ## Next Steps Now that you have your Client API key set up, you can: * [Make Authenticated Requests](/quickstart/authenticated-requests) - Learn how to send authenticated requests * [Explore API Reference](/api-reference/openapi.json) - Browse the full API documentation * [Get Market Data](/quickstart/market-data) - Learn how to fetch market data # Placing Your First Order Source: https://docs.decibel.trade/quickstart/placing-your-first-order Learn the minimum required code to build, sign, and submit your first order transaction ## Placing Your First Order This guide shows you the minimum required code to build, sign, and submit a transaction to place an order on Decibel. ### Prerequisites Before you begin, make sure you have: 1. Generated an API key from [https://app.decibel.trade/api](https://app.decibel.trade/api) 2. Your private key (keep this secure!) 3. APT in your account for gas fees (or set up [Geomi Gas Station](/quickstart/gas-station) to sponsor gas) ### Configuration Variables Before placing an order, you'll need to set these configuration variables: ```bash Mainnet theme={null} PACKAGE=0x50ead22afd6ffd9769e3b3d6e0e64a2a350d68e8b102c4e72e33d0b8cfdfdb06 ``` ```bash Testnet theme={null} PACKAGE=0xe7da2794b1d8af76532ed95f38bfdf1136abfd8ea3a240189971988a83101b7f ``` ### Minimum Required Code Here's the minimal code needed to place an order: ```typescript TypeScript Mainnet theme={null} import { Aptos, AptosConfig, Ed25519Account, Ed25519PrivateKey, Network, } from "@aptos-labs/ts-sdk"; // Configuration const PACKAGE = "0x50ead22afd6ffd9769e3b3d6e0e64a2a350d68e8b102c4e72e33d0b8cfdfdb06"; // Your private key (keep this secure!) const privateKey = "0x..."; // Your private key in hex format // Create account from private key const account = new Ed25519Account({ privateKey: new Ed25519PrivateKey(privateKey), }); // Initialize Aptos client const aptosConfig = new AptosConfig({ network: Network.MAINNET, }); const aptos = new Aptos(aptosConfig); // Build the transaction const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::place_order_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (PerpMarket object address) 5670000000, // price (5.67 with 9 decimals) 1000000000, // size (1.0 with 9 decimals) true, // isBuy (true for buy, false for sell) 0, // timeInForce (0 = GoodTillCanceled, 1 = PostOnly, 2 = ImmediateOrCancel) false, // isReduceOnly null, // clientOrderId (optional) null, // stopPrice (optional) null, // tpTriggerPrice (optional) null, // tpLimitPrice (optional) null, // slTriggerPrice (optional) null, // slLimitPrice (optional) null, // builderAddress (optional) null, // builderFees (optional) ], }, }); // Sign the transaction const senderAuthenticator = aptos.transaction.sign({ signer: account, transaction, }); // Submit the transaction const pendingTransaction = await aptos.transaction.submit.simple({ transaction, senderAuthenticator, }); // Wait for confirmation const executedTx = await aptos.waitForTransaction({ transactionHash: pendingTransaction.hash, }); console.log("Order placed successfully!"); console.log("Transaction Hash:", executedTx.hash); ``` ```typescript TypeScript Testnet theme={null} import { Aptos, AptosConfig, Ed25519Account, Ed25519PrivateKey, Network, } from "@aptos-labs/ts-sdk"; // Configuration const PACKAGE = "0xe7da2794b1d8af76532ed95f38bfdf1136abfd8ea3a240189971988a83101b7f"; // Your private key (keep this secure!) const privateKey = "0x..."; // Your private key in hex format // Create account from private key const account = new Ed25519Account({ privateKey: new Ed25519PrivateKey(privateKey), }); // Initialize Aptos client const aptosConfig = new AptosConfig({ network: Network.TESTNET, }); const aptos = new Aptos(aptosConfig); // Build the transaction const transaction = await aptos.transaction.build.simple({ sender: account.accountAddress, data: { function: `${PACKAGE}::dex_accounts_entry::place_order_to_subaccount`, typeArguments: [], functionArguments: [ "0x123...abc", // subaccountAddr "0x456...def", // marketAddr (PerpMarket object address) 5670000000, // price (5.67 with 9 decimals) 1000000000, // size (1.0 with 9 decimals) true, // isBuy (true for buy, false for sell) 0, // timeInForce (0 = GoodTillCanceled, 1 = PostOnly, 2 = ImmediateOrCancel) false, // isReduceOnly null, // clientOrderId (optional) null, // stopPrice (optional) null, // tpTriggerPrice (optional) null, // tpLimitPrice (optional) null, // slTriggerPrice (optional) null, // slLimitPrice (optional) null, // builderAddress (optional) null, // builderFees (optional) ], }, }); // Sign the transaction const senderAuthenticator = aptos.transaction.sign({ signer: account, transaction, }); // Submit the transaction const pendingTransaction = await aptos.transaction.submit.simple({ transaction, senderAuthenticator, }); // Wait for confirmation const executedTx = await aptos.waitForTransaction({ transactionHash: pendingTransaction.hash, }); console.log("Order placed successfully!"); console.log("Transaction Hash:", executedTx.hash); ``` ```python Python Mainnet theme={null} from aptos_sdk.account import Account from aptos_sdk.client import RestClient from aptos_sdk.account_address import AccountAddress # Configuration PACKAGE = "0x50ead22afd6ffd9769e3b3d6e0e64a2a350d68e8b102c4e72e33d0b8cfdfdb06" FULLNODE_URL = "https://api.mainnet.aptoslabs.com/v1" # Your private key (keep this secure!) private_key = "0x..." # Your private key in hex format # Create account from private key account = Account.load_key(private_key) # Initialize Aptos client rest_client = RestClient(FULLNODE_URL) # Build the transaction transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::place_order_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (PerpMarket object address) 5670000000, # price (5.67 with 9 decimals) 1000000000, # size (1.0 with 9 decimals) True, # isBuy (true for buy, false for sell) 0, # timeInForce (0 = GoodTillCanceled, 1 = PostOnly, 2 = ImmediateOrCancel) False, # isReduceOnly None, # clientOrderId (optional) None, # stopPrice (optional) None, # tpTriggerPrice (optional) None, # tpLimitPrice (optional) None, # slTriggerPrice (optional) None, # slLimitPrice (optional) None, # builderAddress (optional) None, # builderFees (optional) ], }, ) # Sign the transaction signed_transaction = account.sign(transaction) # Submit the transaction pending_transaction = rest_client.submit_transaction(signed_transaction) # Wait for confirmation executed_tx = rest_client.wait_for_transaction(pending_transaction) print("Order placed successfully!") print(f"Transaction Hash: {executed_tx['hash']}") ``` ```python Python Testnet theme={null} from aptos_sdk.account import Account from aptos_sdk.client import RestClient from aptos_sdk.account_address import AccountAddress # Configuration PACKAGE = "0xe7da2794b1d8af76532ed95f38bfdf1136abfd8ea3a240189971988a83101b7f" FULLNODE_URL = "https://api.testnet.aptoslabs.com/v1" # Your private key (keep this secure!) private_key = "0x..." # Your private key in hex format # Create account from private key account = Account.load_key(private_key) # Initialize Aptos client rest_client = RestClient(FULLNODE_URL) # Build the transaction transaction = rest_client.build_transaction( sender=account.address(), payload={ "function": f"{PACKAGE}::dex_accounts_entry::place_order_to_subaccount", "type_arguments": [], "function_arguments": [ "0x123...abc", # subaccountAddr "0x456...def", # marketAddr (PerpMarket object address) 5670000000, # price (5.67 with 9 decimals) 1000000000, # size (1.0 with 9 decimals) True, # isBuy (true for buy, false for sell) 0, # timeInForce (0 = GoodTillCanceled, 1 = PostOnly, 2 = ImmediateOrCancel) False, # isReduceOnly None, # clientOrderId (optional) None, # stopPrice (optional) None, # tpTriggerPrice (optional) None, # tpLimitPrice (optional) None, # slTriggerPrice (optional) None, # slLimitPrice (optional) None, # builderAddress (optional) None, # builderFees (optional) ], }, ) # Sign the transaction signed_transaction = account.sign(transaction) # Submit the transaction pending_transaction = rest_client.submit_transaction(signed_transaction) # Wait for confirmation executed_tx = rest_client.wait_for_transaction(pending_transaction) print("Order placed successfully!") print(f"Transaction Hash: {executed_tx['hash']}") ``` ### What This Code Does 1. **Imports**: Imports the necessary classes from `@aptos-labs/ts-sdk` (TypeScript) or `aptos-sdk` (Python) 2. **Account Setup**: Creates an account from your private key 3. **Client Initialization**: Initializes the Aptos client with the network configuration 4. **Transaction Building**: Builds a transaction calling `place_order_to_subaccount` with your order parameters 5. **Signing**: Signs the transaction with your private key 6. **Submission**: Submits the signed transaction to the blockchain 7. **Confirmation**: Waits for the transaction to be confirmed ### Next Steps For more detailed information, see: * [Place Order Transaction](/developer-hub/on-chain/order-management/place-order) - Complete documentation for placing orders * [Formatting Prices and Sizes](/developer-hub/on-chain/overview/formatting-prices-sizes) - Learn how to format prices and sizes correctly * [Optimized Transaction Building](/developer-hub/on-chain/overview/optimized-building) - Learn how to build transactions synchronously for better performance * [Authenticated Requests](/quickstart/authenticated-requests) - Overview of authenticated requests **Note:** This example uses mock addresses for `subaccountAddr` and `marketAddr`. In a real application, you'll need to: - Get your Trading Account address (see [Create Trading Account](/developer-hub/on-chain/account-management/create-subaccount)) - Get the market address from the `v1/markets` API endpoint - Format prices and sizes correctly using market configuration (see [Formatting Prices and Sizes](/developer-hub/on-chain/overview/formatting-prices-sizes)) **Security:** Never expose your private key in client-side code or commit it to version control. Use environment variables or secure key management systems. # TypeScript Starter Kit Source: https://docs.decibel.trade/quickstart/typescript-starter-kit Place orders via REST API and stream market data via WebSocket. Get your first trade in under 10 minutes, then customize the bot for your strategy. A streamlined quick-start for the Decibel TypeScript starter kit: set up fast, then customize. Follow the exact steps to install, configure, and place your first order. Understand Decibel's three-tier account model, execution queue, and funding. Customize markets, order logic, and Trading Accounts for your own strategy. ## Part 1: Get Your First Trade under 5 min Follow these steps exactly to get your first trade running. ### 1. Prerequisites * [Node.js](https://nodejs.org/) 18+ * [Petra Wallet](https://petra.app/) browser extension (recommended, optional thanks to Aptos Connect) * [Git](https://git-scm.com/downloads) * [Aptos CLI](https://aptos.dev/build/cli#-install-the-aptos-cli) (recommended) ### 2. Get Your Credentials You need two things: an API Wallet (for signing transactions) and an API Key (for authenticated API requests). #### Create API Wallet 1. Go to [app.decibel.trade/api](https://app.decibel.trade/api) 2. Connect your Petra Wallet or "Continue with Google" 3. Click **"Create API Wallet"** Create API Wallet Example 4. Copy the Private Key immediately (you only see it once) 5. Also save the Wallet Address shown on the same screen Store your private key securely! Anyone with this key can access your funds. #### Create API Key (Bearer Token) The API Key is used for authenticated requests to the Decibel REST API. You'll get this from Geomi (Aptos Build). 1. Sign up or log in at [geomi.dev](https://geomi.dev) * Click "Continue with Google" or enter your email 2. Create or select a project * If you're new, you'll see "No resources yet", that's fine! * Your project dashboard will show available resources 3. Add an API Key resource Geomi Dashboard * Click the **"API Key"** card (find it under "Add more resources to your project") 4. Fill out the API Key form: Create API Key Form * **API Key Name:** Choose a name (e.g., `decibel` or `my-trading-bot`) * **Network:** Select **"Decibel Devnet"** from the dropdown (important!) * **Description:** Optional, add a note about what this key is for (150 chars max) * **Client usage:** Leave this **OFF** (unless you're building a web/mobile app) * Click **"Create New API Key"** 5. Copy your Bearer Token Get Bearer Token * After creation, you'll see your API key in the "API Keys" table * Find the **"Key secret"** column, this is your Bearer token * Click the copy icon next to the masked key (shows as `*****...*****`) This "Key secret" is your `API_BEARER_TOKEN`. It's the full Bearer token, not just the key name. ### 3. Configure the Project ```bash Clone and Install theme={null} # Clone the repo git clone https://github.com/tippi-fifestarr/testetna.git cd testetna # Install dependencies npm install # Create env file cp .env.example .env ``` Open `.env` and paste your credentials: ```bash .env theme={null} API_WALLET_PRIVATE_KEY=YOUR_COPIED_KEY_HERE API_WALLET_ADDRESS=0xYOUR_WALLET_ADDRESS_HERE API_BEARER_TOKEN=YOUR_BEARER_TOKEN_HERE ``` **Quick checklist:** * `API_WALLET_PRIVATE_KEY`: From Decibel App (Create API Wallet). Both formats are accepted: * AIP-80 format: `ed25519-priv-0x...` (as copied from the Decibel app) * Hex format: `0x...` (64 hex characters) Paste the key exactly as you copied it — do not add or remove the `ed25519-priv-` prefix. * `API_WALLET_ADDRESS`: From Decibel App (Create API Wallet) * `API_BEARER_TOKEN`: From Geomi (Create API Key, "Key secret" column) ### 4. Run the "Quick Win" This script handles everything: funding (via private faucet), account creation, minting USDC, depositing, and placing a trade. ```bash theme={null} npm run quick-win ``` **If you see "🎉 Order Placement Complete!", congratulations. The code works.** ## Part 2: Mental Model & Architecture 🏗️ Trading on Decibel has specific mechanics that differ from CEXs and many DEXs. Here are 5 key concepts for API traders. **Jump to [Part 3](#part-3) if you're ready to start customizing your code.** You can always come back here later. ### 1. The Three-Tier Account Model Decibel uses a three-tier account structure for programmatic trading: | Tier | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Primary Wallet** | Your login account. Used to access Decibel App and create API Wallets. | | **API Wallet** | A separate wallet for API trading. Holds APT for gas fees and signs all trading transactions. This is your `API_WALLET_ADDRESS`. | | **Trading Account** | Created from your API Wallet. Holds USDC for trading collateral. Address is extracted from transaction events and written to `.env` as `SUBACCOUNT_ADDRESS`. | **Flow:** Primary Wallet → Create API Wallet → Create Trading Account → Deposit USDC → Trade. Three-tier account model For API traders, you primarily interact with the API Wallet (not the Primary Wallet). Most users will have a single Trading Account, though you can create multiple for different strategies. ### 2. Async Execution (The Queue) Decibel is an on-chain CLOB (Central Limit Order Book). | Platform | Behavior | | ----------- | ---------------------------------------------------------------------------- | | **CEX** | `response = placeOrder()` → Returns "Filled" | | **Decibel** | `response = placeOrder()` → Returns "Transaction Hash" (Ticket to the Queue) | Execution is asynchronous. The REST response confirms *submission*, not *fill*. Use the [WebSocket streams](/api-reference/websocket/overview) for execution updates. ### 3. "Lazy" Continuous Funding * **Traditional:** Pay funding every 8 hours * **Decibel:** Funding ticks every second (continuous accrual) You only "pay" (settle) funding when you modify or close the position. Your `Unrealized PnL` includes accrued funding debt. Watch it closely to avoid liquidation. ### 4. Reduce-Only Logic Decibel implements strict "Close First" logic. A Reduce-Only order will never flip your position (e.g., Long 1 → Short 1). It caps execution at your current size, preventing accidental exposure when closing positions aggressively. See [Place Order](/developer-hub/on-chain/order-management/place-order) for implementation details. ### 5. Bulk Orders (Unique Optimization) For Market Makers and HFTs: You can update multiple orders in a single transaction, saving gas and getting atomic updates for spread management. See [Place Bulk Order](/developer-hub/on-chain/order-management/place-bulk-order) for implementation details. ## Part 3: Make It Yours Now that you have a working baseline, here's how to adapt this code for your actual strategy. ### How to Trade a Different Market Open `src/5-place-order.ts`. Find the "Configuration" section. **Change this:** ```typescript theme={null} const marketName = config.MARKET_NAME || 'BTC/USD'; ``` **To this:** ```typescript theme={null} const marketName = 'ETH/USD'; // or SOL/USD, APT/USD, etc. ``` Run `npm run setup` to see a list of all available market names. Market names use the format `SYMBOL/USD` (not `SYMBOL-PERP`). ### How to Change Your Order Logic Open `src/5-place-order.ts`. Find the "Order Parameters" section. **Change this:** ```typescript theme={null} const userPrice = 50000; const userSize = 0.001; const isBuy = true; ``` **To your own logic:** ```typescript theme={null} // Example: A simple moving average bot might look like this const userPrice = calculatedMovingAverage; const userSize = riskManagementSize; const isBuy = signal === 'BULLISH'; ``` ### Focus on Order Management After running `quick-win`, you have a funded Trading Account ready to use. You can now focus on: * `src/5-place-order.ts`: Customize your trading strategy * `src/6-query-order.ts`: Check order status You don't need to create a new Trading Account for every trade. Once you have USDC deposited (from `quick-win`), you can run `5-place-order` and `6-query` repeatedly using the same Trading Account. ### How to Use a Different Trading Account If you want to use a specific Trading Account (e.g., for a different strategy): 1. Create a new one: `npm run create-subaccount` 2. The script automatically updates your `.env` file with the new `SUBACCOUNT_ADDRESS` 3. Run `npm run deposit-usdc` to fund it **How the Trading Account script works:** * Calls `create_new_subaccount`, which creates a non-primary Trading Account (random address) * Extracts the Trading Account address from the `SubaccountCreatedEvent` in the transaction events * Verifies the address via the API (with up to 5 retries for indexer lag) * Writes the address to your `.env` file **To manually select a different Trading Account:** * After running `create-subaccount`, check the list of Trading Accounts it prints * Manually edit `.env` and set `SUBACCOUNT_ADDRESS` to the address you want * Or modify `src/2-create-subaccount.ts` to change the selection logic ## Part 4: What's Next? 🚀 Build a script to track `Unrealized PnL` + `Accrued Funding` to avoid liquidation. Use `src/7-websocket-updates.ts` to listen to the orderbook and place Maker orders. Look into `Post-Only` and `Reduce-Only` params in the API docs for advanced control. ### Resources Complete Decibel documentation Alternative guide with Testnet examples Get help from the community Fund your API Wallet with Testnet APT for gas # Amps: Season 1 Source: https://docs.decibel.trade/rewards/amps Decibel's native points program. Amps accrue daily based on trading activity, liquidity provision, and ecosystem contributions — and are a primary input for TGE token distribution. Amps are Decibel's native points that accrue based on your trading activity, liquidity provision, and ecosystem contributions. **Amps are a primary input Decibel uses when evaluating token distribution at TGE**. Season 1 launched alongside Mainnet with a transparent daily capped emission schedule, following the close of Season 0 (Pre-Deposit). Track your Amps in real time on the [Season 1 dashboard →](https://app.decibel.trade/points) **Read the announcement:** [The Decibel Points Program Is Here →](https://x.com/DecibelTrade/status/2026749177796215270) ## How Amps Are Accrued Amps are accrued daily across core categories using a multi-dimensional scoring model designed to prioritize organic activity over raw volume. ### Trading Activity Score Amps received from organic trading reflect the quality and consistency of your activity, not just the size: * **Active Trading.** Rewards scale with trading frequency, adjusted to distinguish genuine activity from noise. * **Leverage Weighting.** Thoughtful risk-taking and high-conviction positions are acknowledged in the scoring. * **Duration Multiplier.** Holding positions longer earns additional weight. Rapid in-and-out cycling is deprioritized. * **Market Exploration.** Trading exotic pairs and less liquid markets grants bonus multipliers. * **Liquidation Recovery.** Active users can re-engage and continue earning Amps even after market volatility. * **Consistency Bonus.** Daily trading streaks unlock progressive bonuses that compound over time. ### Liquidity Provision (DLP) Score Providing capital to the Decibel Liquidity Provider (DLP) Vault or user-managed vaults allows users to accrue a dedicated portion of daily emissions: * **Depth & Duration.** Amps scale with the amount of capital committed and the length of time capital remains in the DLP Vault. * **Anti-Tourism.** A withdrawal mechanism discourages short-term capital rotation and rewards long-term providers. ### Referrals & Affiliate Score A dedicated daily emission pool of Amps flows to community builders who onboard new users. Amps from referrals scale based on the measurable activity of the users you bring in. See the [Referral Program](/rewards/referral-program) page for details on how the Referral Program works. ## Integrity & Sybil Resistance Decibel is built with "Incentive Resilience" to protect the community from traders trying to game the rewards system: * **Opaque Formulas.** Exact scoring formulas are deliberately undisclosed to prevent reverse-engineering and gaming. * **Sybil Resistance.** Behavior analysis, device signals, and network graphs are used to identify and disqualify non-organic activity. * **Platform Health.** Penalties exist for any behavior that degrades the trading experience for other users. ## Amps & Token Distribution * Amps are a primary factor in determining access to protocol tokens (e.g., DCBL), with a significant portion of supply expected to be allocated to Season 0 and Season 1 participants. * The system is designed to reward consistent contributors and reduce last-minute positioning. **Risk Warning:** DeFi protocols and perpetual trading carry significant risks. Always perform your own research (DYOR). Participation in the Amps program does not guarantee financial gain. # Live Campaigns Source: https://docs.decibel.trade/rewards/campaigns/live Campaigns that are active today and distributing rewards — First Trade on Us; Liquidation Rebate; and Maker Rebate. These campaigns are active today and distributing rewards. See [How Rewards Work](/rewards/overview#how-rewards-work) for the claim flow. **Active now — distributing rewards today.** The campaigns below are live. Review and claim all eligible rewards from the **/rewards** page in the [Decibel app](https://app.decibel.trade/trade); you may also see **"Claim now" pop-ups** surfacing rewards as you trade. ## First Trade on Us Live Try a real BTC trade with **zero downside**. Deposit \$250–\$5,000 in USDC to receive one Trade on Us credit for a **sponsored 2-minute BTC position**. If the position closes in profit, the profit is credited to your Decibel account. If it closes at a loss, nothing is deducted from your deposit. Your deposit remains available to trade, but withdrawals are unavailable for the period of time corresponding to the leverage selected. | | | | ---------------------- | ------------------------------------------------------------------ | | **Reward** | Profit generated by the sponsored 2-minute BTC position | | **Duration** | July 21 – October 21, 2026 | | **Who's Eligible** | Traders who have not previously claimed a First Trade on Us credit | | **Entry Requirements** | Deposit \$250 – \$5,000 in USDC and choose position leverage | **How it works:** Log in or sign up at [app.decibel.trade](https://app.decibel.trade/), then visit [app.decibel.trade/rewards/first-trade-on-us](https://app.decibel.trade/rewards/first-trade-on-us). Deposit between \$250 and \$5,000 in USDC to receive one trade-on-us credit. Choose from leverage options (20x, 30x, or 40x). Your deposit amount determines the size of the sponsored BTC position, from \$50 to \$1,100. Your selected leverage determines how long your deposit has to remain in your trade balance. With higher leverage, you unlock more potential profit from the same BTC price movement (see the table below). Once you've deposited and chosen your leverage (and corresponding lock period), confirming your selections will redeem your Trade on Us credit and open your position. The BTC position will remain open for 2 minutes and then will be closed. The direction — long or short — is set automatically; you don't place or manage the trade yourself. BTC's price will move during the two-minute position. If the position closes in profit, the profit is credited to your Decibel account in USDC. If it closes at a loss, nothing is deducted from your deposit. The most the trade can cost you is \$0. Your deposit (and any profit from your trade) remains your USDC. You cannot withdraw it until your selected period ends, but it remains available for you to place your own trades on Decibel. Any trades you place yourself are separate from the sponsored position and carry normal trading risk. Losses from your own trades are not covered by the campaign. When your selected period ends, you can withdraw any remaining funds. **Leverage by Lock Period:** | Lock Period | Leverage | | ----------- | -------- | | 1 day | 20x | | 4 days | 30x | | 7 days | 40x | **Eligibility:** * Must be 18 or over. * Not available in the United States, Ontario (Canada), or other restricted jurisdictions. Other terms and eligibility conditions apply. * Limit one (1) trial credit per wallet address. This campaign is subject to the Decibel [Terms of Service](https://decibel.trade/terms-of-service) and the ["First Trade on Us" Campaign Rules](https://info.decibel.trade/first-trade-rules). *** ## Liquidation Rebate Live Got liquidated? Decibel is giving you a second chance. If your account was liquidated on Decibel, you're eligible for a rebate of 50% of your liquidated margin, up to \$1,000 per account. Redeposit, place a trade, and claim your rebate. This campaign runs each month until the reward pool is exhausted. | | | | ------------------ | --------------------------------- | | **Reward** | 50% of liquidated margin | | **Frequency** | Recurring monthly | | **Who's Eligible** | Any account liquidated on Decibel | | **Cap** | Up to \$1,000 per month | **Eligibility:** * Your account must have been liquidated on Decibel within the current or previous campaign period. * You must redeposit and place at least one new trade after the liquidation event. * Rebate caps at \$1,000 per account per period. **How it works:** * At the end of each monthly period, liquidation events are reviewed, and rebate amounts are calculated for eligible accounts. * Eligible users receive an in-app notification when their rebate is ready to claim. * Visit **/rewards** and click "Claim" to credit the rebate to your trading account. * Unclaimed rebates expire at the end of the month following the qualifying liquidation event. *** ## Maker Rebate Live Decibel rewards accounts that add depth to the order book. If you maintain an **80%+ maker ratio** with bulk orders over a weekly period, you will receive a **0.5 bps rebate** on your maker fill volume. This is a direct rebate paid on top of standard fees… not points, not speculation. | | | | ------------------ | -------------------------------------------- | | **Reward** | `0.5 bps` on bulk order maker fill volume | | **Frequency** | Recurring Weekly | | **Who's Eligible** | Accounts with ≥80% maker ratio & bulk orders | | **Cap** | \$25K per month | **Eligibility:** * Your maker ratio must be 80% or higher for the weekly period, measured by fill volume from bulk (batch) orders. * Only maker fill volume from bulk orders counts. Standard single-order fills are excluded. * If total qualified rebates exceed the weekly cap, payouts are distributed pro rata. **How it works:** * At the end of each week, qualifying maker volume and rebate amounts are calculated per account. * Allocations are published on-chain, and a claim notification appears in-app. * Visit **/rewards** and click "Claim" to credit the rebate to your trading account. * Unclaimed weekly rebates expire at month-end. **Disclaimer:** This communication is for informational purposes only and is not financial, investment, legal, or tax advice. Participation in any Rewards program or Campaign may involve significant risk. This is not an offer or solicitation to buy or sell digital assets. Trading perpetual contracts and engaging with DeFi protocols involves significant risk, including the potential loss of all funds. Past performance isn't indicative of future results. Always do your own research before making any financial decisions. # Potential Campaigns Source: https://docs.decibel.trade/rewards/campaigns/potential Campaigns on Decibel's roadmap that may or may not launch — Trading Competitions and more. These campaigns are on Decibel's roadmap. They are not live, may or may not launch, and details are subject to change. If activated, they would use the same **/rewards** claim flow as live campaigns. **Roadmap only — not committed and not live.** The campaigns below are ideas on Decibel's roadmap that may or may not be activated. Details are subject to change. These cannot be participated in today. If activated, they would use the same **/rewards** claim flow as live campaigns. ## Trading Competitions Potential Compete against other traders for a share of prize pools. Competitions use **ROI-based scoring** with equity-tiered brackets, so it's fair for retail, not just whoever has the biggest account. Two cadences: weekly recurring competitions and larger quarterly flagship events. **Scoring:** ``` ROI = realized_pnl / max(min_threshold, starting_equity + max_net_deposits) ``` The formula prevents mid-competition deposit changes; you can't inflate your base right before the end to spike your ROI. **Equity tiers:** | Bracket | Starting Equity | Prize Share | | ------------ | ------------------ | ----------- | | Lightweight | \< \$1,000 | 20% | | Middleweight | \$1,000 – \$10,000 | 30% | | Heavyweight | \$10,000+ | 50% | * Monday 00:00 UTC → Sunday 23:59 UTC. * Top 5 per tier, plus 2 random draws from anyone with positive PnL. * Minimum \$25,000 cumulative volume during the week to qualify for prizes. * 2-week duration, themed (e.g., "Decibel vs. CEX", BTC-only). * Top 10 per tier with heavier weighting at the top. * Coordinated with KOL outreach, social campaigns, and potential livestreams. **Fair play rules:** * Minimum \$25,000 cumulative volume to qualify for prizes. * Your starting equity minus withdrawals can't drop below your tier cutoff. * Internal accounts (admins, market makers, oracles) are excluded. * Sub-accounts under the same owner are consolidated into one entry. * Top finishers are reviewed before prizes are distributed. **Prize settlement:** * After a competition ends, final standings are calculated and prizes are published on-chain. * Prizes appear as a claimable tile on **/rewards**, following the same claim flow as all other campaigns. ## Other Potential Campaigns | Campaign | Description | Who It's For | | ------------------ | ----------------------------------------------------------------------- | ------------------------- | | Migration Bonus | One-time tiered bonus for traders migrating from other DEXs or CEXs | Hyperliquid / CEX traders | | OI Funding Rebates | Rebate for holding open interest on the paying side of the funding rate | Directional traders | | Volume Milestones | Achievement rewards at \$100K / \$1M / \$10M lifetime volume | All active traders | | Deposit Match | Trading credit when your collateral balance crosses a threshold | New depositors | | Referral Credits | Both referrer and referee earn credit on qualifying activity | Community | | Comeback Bonus | Credit for returning users who've been inactive 30+ days | Returning traders | | Fee Holiday | Temporary zero-fee window after your first deposit | New depositors | A one-time bonus for traders migrating from other decentralized or centralized exchanges, tiered by historical trading volume. To unlock, you'd deposit on Decibel and hit a minimum cumulative volume threshold. Exact tiers and thresholds will be announced before launch. A recurring rebate for traders who hold open interest on the paying side of the funding rate. This rewards genuine directional exposure… accounts running offsetting positions across correlated markets to farm rebates would be excluded. Always-on achievement rewards triggered when you cross lifetime bona fide trading volume thresholds, \$100K, \$1M, and \$10M. Once you qualify, you can claim your reward on **/rewards** at any time. **Deposit Match** pays a trading credit when your collateral exceeds a threshold. **Referral Credits** rewards both you and the people you refer once they hit activity thresholds. **Comeback Bonus** targets users who've been inactive for 30+ days and return with a redeposit. A temporary zero-trading-fee window (e.g., 48 hours) is activated after your first deposit. No claiming needed. Fees are simply waived during the window. *Parameters subject to change. This page is updated as programs and campaigns are added, launched, or modified.* **Disclaimer:** This communication is for informational purposes only and is not financial, investment, legal, or tax advice. Participation in any Rewards program or Campaign may involve significant risk. This is not an offer or solicitation to buy or sell digital assets. Trading perpetual contracts and engaging with DeFi protocols involves significant risk, including the potential loss of all funds. Past performance isn't indicative of future results. Always do your own research before making any financial decisions. # Upcoming Campaigns Source: https://docs.decibel.trade/rewards/campaigns/upcoming Campaigns scheduled to launch on Decibel but not yet live. No upcoming campaigns at this time. Check back here or follow **@DecibelTrade** for launch announcements. See [Live Campaigns](/rewards/campaigns/live) for what's active today, or [Potential Campaigns](/rewards/campaigns/potential) for ideas being explored. # FAQ Source: https://docs.decibel.trade/rewards/faq Common questions about Amps, campaigns, claiming rewards, referrals, and eligibility. Amps are points you receive through trading activity and are a primary input Decibel uses when evaluating token distribution at TGE. Campaign rewards are separate; they pay out USD-denominated stablecoins for specific activities like providing maker liquidity or recovering from a liquidation. You can receive both simultaneously, they don't compete with each other. All campaign rewards are paid in USD-denominated stablecoins and credited directly to your trading account balance. The Card Vault campaign was an exception; those rewards were physical PSA-graded cards shipped via Courtyard.io. Most campaigns are automatic. If you meet the eligibility criteria, your reward is calculated and made available for you to claim. Some campaigns require you to register or opt in before the campaign period starts — the Card Vault campaign did, for example. Yes. There is no limit to how many campaigns you can be eligible for simultaneously. Each campaign is independent. Your trading activity may qualify you for several at the same time. Yes. Recurring campaigns like Maker Rebate and Liquidation Rebate have expiry windows, typically at month-end for weekly rebates, and end of the following month for monthly rebates. You'll see the expiry date on each tile in **/rewards**. Yes. Claimed rewards credit to your trading account balance and behave like any other funds. You can trade with them or withdraw. There's no lock-up or vesting period. Connect your wallet on the [Season 1 dashboard](https://app.decibel.trade/points) and complete \$25,000 in trading volume. Your 5 referral codes will then appear automatically. Share them with anyone you want to invite. You accrue a share of your invitees' Amps, drawn from a dedicated daily emission pool of Amps. Referral Amps scale with the actual trading activity of the people you bring in, not just the number of sign-ups. Scoring formulas are deliberately undisclosed to prevent gaming and abuse of the points program. The system is designed to reward genuine trading activity, liquidity provision, and community contribution. Only fill volume from bulk (batch) orders where you're on the maker side. Standard single-order fills are not included. Your maker ratio for the week must be 80% or higher to qualify. For trading competitions, all sub-accounts under the same owner are consolidated into a single entry. For other campaigns, eligibility is generally evaluated at the account level. New campaigns are announced on Decibel's social channels and appear on the **/rewards** page. This documentation page is also updated when campaigns change status. Follow **@DecibelTrade** on X for the latest. Each campaign has a fixed reward pool. If it's exhausted before all eligible users claim, the claim button will be unavailable until the pool is refilled. Campaigns are funded on a recurring basis. Campaign and Amps eligibility follows the same eligibility criteria as the Decibel exchange. If you are eligible to trade on Decibel, you're eligible to participate. Yes. Reward rates, eligibility thresholds, Amps emissions, and claim windows may be adjusted at any time, without notice, at our sole discretion. Changes always apply going forward; they never retroactively affect rewards that have already been settled. # Rewards Programs Source: https://docs.decibel.trade/rewards/overview Everything you can earn on Decibel — from the Amps points program and referral rewards to targeted trading campaigns. Everything you can receive on Decibel, from the Amps points program and referral rewards to targeted trading campaigns, is covered here. This page explains how each program works, what's live today, what's coming next, and how to claim. By participating in any Decibel Campaign or the Amps Program, including those detailed below, you agree to Decibel's [Terms of Service](https://decibel.trade/terms-of-service), which are incorporated herein. Please review the Terms carefully before participating. As detailed in the Terms, we reserve the right to disqualify any Rewards Campaign or Amps Program user for any reason in our sole discretion, and to modify, suspend, or cancel any Rewards Program or Campaign at any time without prior notice. Daily points accrual based on trading, liquidity, and referrals. Primary input for TGE token distribution. Invite traders and earn 10% of their Amps from a dedicated daily emission pool. USD-denominated stablecoin rewards for specific activities — maker rebates, liquidation recovery, competitions, and more. Common questions about Amps, campaigns, claiming, referrals, and eligibility. ## How Rewards Work Decibel has two reward systems that work alongside each other. **Amps** are points that accrue daily based on your trading activity and contributions to the protocol. Amps are points you earn through trading and activity on Decibel. At TGE, Amps holders will receive priority consideration for token distribution, the more you've earned, the better positioned you are. **Campaigns** allow eligible users to claim rewards in usDCBL, Decibel's USD-denominated stablecoin, and offer rewards for specific activities like providing maker liquidity or recovering from a liquidation. Campaign rewards are claimed through the ***/rewards*** page and credited directly to your trading account balance: When you have unclaimed rewards, a banner appears in the [Decibel app](https://app.decibel.trade/trade) showing your total available amount of unclaimed rewards. Visit **/rewards** to see every campaign you're eligible for. Each Campaign will show a status: Not Eligible, In Progress, Ready to Claim, Claimed, or Expired. Tap "Claim" on any Ready to Claim tile. When you claim, your rewards will be credited to your trading account in a single onchain transaction. Your balance updates immediately. Start trading with your rewards right away. Your claim history, including amounts, dates, and transaction hashes, is available on the **/rewards** page. Campaign rewards are distributed in USD-denominated stablecoins and settled on Aptos. Amps accrue automatically and are visible on the [Season 1 dashboard](https://app.decibel.trade/points). Most recurring campaigns have an **expiry window**. Unclaimed weekly rewards typically expire at month-end, and monthly rewards expire at the end of the following month. If you do not claim your rewards before the expiry window closes, you will not be able to claim those rewards. Check **/rewards** regularly so you don't miss a claim. # Referral Program Source: https://docs.decibel.trade/rewards/referral-program Invite traders to Decibel and earn 10% of their Amps from a dedicated daily emission pool. Invite traders to Decibel and earn additional Amps. The Referral Program draws from a dedicated daily emission pool of Amps: the more active your invitees are, the more Amps you can receive. To start, you will be given 5 referral codes that allow you to invite others into Decibel's Mainnet Beta. ## Generating Your Referral Code Go to the [Season 1 dashboard](https://app.decibel.trade/points) and connect your wallet. Your 5 referral codes will be displayed on the Points dashboard automatically. Share the code with anyone you want to invite to Decibel. ## Using a Referral Code When your referred invitees first connect their wallet to Decibel, they will be prompted to enter a referral code. Click **Unlock Access** to bind it to your account. Once bound, the referral link is permanent between referrer and referee. ## Referral Bonus You receive **10% of your invitees' Amps**, updated daily and visible on the [Season 1 dashboard](https://app.decibel.trade/points). Referral Amps scale based on the sustained engagement and measurable bona fide trading activity of the users you onboard, not just the number of sign-ups. Referral codes are intentionally limited to ensure quality over quantity. Referral Amps are drawn from a dedicated daily emission pool and do not reduce your invitees' Amps. Both parties benefit from the relationship. # Audits Source: https://docs.decibel.trade/security/audits Third-party security audit reports for Decibel smart contracts. Decibel is committed to security. All critical smart contracts undergo third-party security audits before deployment. ## Perps Exchange Smart Contract Audit The perps contract audit was conducted by OtterSec. Download the full audit report (PDF) ## Liquidations and Vaults Smart Contract Audit The liquidations and vaults contract audit was conducted by OtterSec. Download the full audit report (PDF) ## Orderbook Audit The orderbook contract audit was conducted by OtterSec. Download the full audit report (PDF) ## Pre-deposit Contract Audit The pre-deposit contract audit was conducted by OtterSec. Download the full audit report (PDF) ## Spot Exchange Smart Contract Audit The spot exchange contract audit was conducted by OtterSec. Download the full audit report (PDF) # Advanced Source: https://docs.decibel.trade/typescript-sdk/advanced Gas price management, fee payer behavior, and time synchronization ## Gas price manager Use `GasPriceManager` to fetch and cache gas estimates and pass them to the Write SDK for faster, predictable transaction building: ```ts theme={null} import { GasPriceManager, DecibelWriteDex, TESTNET_CONFIG, } from "@decibeltrade/sdk"; import { Ed25519Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk"; const gas = new GasPriceManager(TESTNET_CONFIG, { multiplier: 2, // default multiplier applied to estimates refreshIntervalMs: 60_000, // refresh cadence }); await gas.initialize(); const account = new Ed25519Account({ privateKey: new Ed25519PrivateKey(process.env.PRIVATE_KEY!), }); const write = new DecibelWriteDex(TESTNET_CONFIG, account, { nodeApiKey: process.env.APTOS_NODE_API_KEY!, // Required gasPriceManager: gas, }); ``` Stop the manager when your app unmounts: ```ts theme={null} gas.destroy(); ``` ## Gas sponsorship * By default, transactions are self-pay (the user pays gas in APT). * To sponsor gas via [Geomi Gas Station](/quickstart/gas-station), add `gasStationApiKey` to your config: ```ts theme={null} const config = { ...TESTNET_CONFIG, gasStationApiKey: process.env.GAS_STATION_API_KEY! }; const write = new DecibelWriteDex(config, account); ``` ## Time synchronization If client clocks are skewed, set `timeDeltaMs` to shift local time used when building transactions: ```ts theme={null} const write = new DecibelWriteDex(TESTNET_CONFIG, account, { timeDeltaMs: serverDeltaMs, }); ``` You can compute `serverDeltaMs = serverTimeMs - Date.now()` using your own time endpoint. # Configuration Source: https://docs.decibel.trade/typescript-sdk/configuration Network presets and configuration for the Decibel TypeScript SDK ## DecibelConfig * network: Aptos network identifier * fullnodeUrl: Aptos fullnode HTTP endpoint * tradingHttpUrl: Decibel trading REST base URL * tradingWsUrl: Decibel trading WebSocket URL * gasStationUrl: Base URL override for the Gas Station API (only needed for custom networks) * gasStationApiKey: [Geomi Gas Station](/quickstart/gas-station) API key for sponsored transactions * gasStationAddress: on-chain fee-payer address of that Gas Station; only required for encrypted submission * deployment: on-chain package and addresses (package, predepositPackage, campaignPackage, usdc, testc, perpEngineGlobal, dlpVault, dlpShare; fftCampaignAddr optional) * chainId: optional preconfigured chain id to accelerate build/sign ## Custom config example ```ts theme={null} import { type DecibelConfig } from "@decibeltrade/sdk"; import { Network } from "@aptos-labs/ts-sdk"; const CUSTOM: DecibelConfig = { network: Network.CUSTOM, fullnodeUrl: "https://fullnode.example.com/v1", tradingHttpUrl: "https://api.example.com/decibel", tradingWsUrl: "wss://api.example.com/decibel/ws", gasStationUrl: "https://api.example.com/gs/v1", // optional: enables gas sponsorship gasStationApiKey: process.env.GAS_STATION_API_KEY, // optional: enables gas sponsorship deployment: { package: "0x...package", predepositPackage: "0x...predeposit", campaignPackage: "0x...campaign", usdc: "0x...usdc", testc: "0x...testc", perpEngineGlobal: "0x...global", dlpVault: "0x...dlpVault", dlpShare: "0x...dlpShare", }, chainId: 204, // optional }; ``` ## Gas Station (Sponsored Transactions) To sponsor gas fees for your users via [Geomi Gas Station](/quickstart/gas-station), add `gasStationApiKey` to your config: ```ts theme={null} const config = { ...TESTNET_CONFIG, gasStationApiKey: process.env.GAS_STATION_API_KEY!, }; const write = new DecibelWriteDex(config, account); ``` When `gasStationApiKey` is set, the SDK automatically submits all transactions through the Gas Station for fee sponsorship. Users don't need APT for gas. To disable sponsorship, simply omit `gasStationApiKey` from the config. ## Encrypted submission Pass `defaultEncrypted: true` to `DecibelWriteDex` to submit front-run-sensitive writes as encrypted pending transactions. The flag is exposed as a readonly property on the instance, and submission still downgrades to plaintext when the fullnode exposes no encryption key. An encrypted transaction bakes the literal fee-payer address into its payload at build time, so a Gas Station can only sponsor one when `gasStationAddress` is also set. Use `configSupportsEncryptedSubmission(config)` to check that before promising the user encryption: ```ts theme={null} import { configSupportsEncryptedSubmission } from "@decibeltrade/sdk"; const config = { ...TESTNET_CONFIG, gasStationApiKey: process.env.GAS_STATION_API_KEY!, gasStationAddress: process.env.GAS_STATION_ADDRESS!, // omit this and writes go out in plaintext }; const write = new DecibelWriteDex(config, account, { defaultEncrypted: configSupportsEncryptedSubmission(config), }); ``` ## Node API keys Pass `nodeApiKey` to `DecibelReadDex` or `DecibelWriteDex` for fullnode rate limits and performance.\ Under the hood, the SDK sends it as `Authorization: Bearer ` on outbound HTTP requests: ```ts theme={null} const read = new DecibelReadDex(TESTNET_CONFIG, { nodeApiKey: process.env.APTOS_NODE_API_KEY!, // Required }); const write = new DecibelWriteDex(TESTNET_CONFIG, account, { nodeApiKey: process.env.APTOS_NODE_API_KEY!, // Required }); ``` # Error responses Source: https://docs.decibel.trade/typescript-sdk/error-responses Error codes and handling for TypeScript SDK functions ## place\_order\_to\_subaccount | Error Code | Module | Error Name | When It Occurs | | ---------- | ----------------------- | -------------------------------------------------------------- | ---------------------------------------- | | 1 | builder\_code\_registry | EINVALID\_AMOUNT | Builder fees \<= 0 | | 1 | tp\_sl\_utils | EINVALID\_TP\_SL\_PARAMETERS | Invalid TP/SL parameters | | 1 | order\_placement\_utils | EINVALID\_MATCH\_COUNT | Match count validation error | | 1 | clearinghouse\_perp | EINVALID\_ARGUMENT | Invalid argument | | 2 | clearinghouse\_perp | EINVALID\_SIZE\_IS\_ZERO | Size == 0 in settlement | | 2 | builder\_code\_registry | EBUILDER\_NOT\_REGISTERED | Builder not registered | | 2 | async\_matching\_engine | EINVALID\_TP\_SL\_FOR\_REDUCE\_ONLY | TP/SL with reduce\_only | | 3 | clearinghouse\_perp | EINVALID\_SIZE\_IS\_TOO\_LARGE | Size too large | | 3 | dex\_accounts | ENOT\_SUBACCOUNT\_OWNER\_OR\_LACKS\_PERP\_TRADING\_PERMISSIONS | Signer lacks trading permissions | | 3 | async\_matching\_engine | EINVALID\_TP\_SL\_WITH\_TRIGGER\_CONDITION | TP/SL with stop\_price | | 4 | builder\_code\_registry | EINVALID\_MAX\_FEE | Builder fees exceed max fee | | 4 | perp\_market\_config | ESIZE\_NOT\_RESPECTING\_MIN\_SIZE | Size \< min\_size | | 4 | perp\_engine | EMARKET\_HALTED | Exchange is not open | | 4 | clearinghouse\_perp | EINVALID\_PRICE\_IS\_ZERO | Price == 0 | | 4 | async\_matching\_engine | EINVALID\_STOP\_PRICE | Invalid stop\_price | | 5 | clearinghouse\_perp | EINVALID\_PRICE\_IS\_TOO\_LARGE | Price too large | | 5 | pending\_order\_tracker | E\_INVALID\_REDUCE\_ONLY\_ORDER | Invalid reduce-only order | | 5 | async\_matching\_engine | EINVALD\_WORK\_UNITS\_PER\_TRIGGER | Invalid work units | | 6 | perp\_market\_config | EPRICE\_NOT\_RESPECTING\_TICKER\_SIZE | Price not multiple of ticker\_size | | 6 | clearinghouse\_perp | EINVALID\_SETTLE\_RESULT | Invalid settlement result | | 7 | clearinghouse\_perp | ESELF\_TRADE\_NOT\_ALLOWED | Taker == maker | | 8 | pending\_order\_tracker | EMAX\_FIXED\_SIZED\_PENDING\_REQS\_HIT | Max fixed-size pending requests exceeded | | 8 | clearinghouse\_perp | ENOT\_REDUCE\_ONLY | Not reduce-only when expected | | 8 | dex\_accounts | ESUBACCOUNT\_IS\_NOT\_ACTIVE | Subaccount is inactive | | 10 | perp\_market\_config | EINVALID\_PRICE | Price == 0 | | 10 | pending\_order\_tracker | EINVALID\_TP\_SL\_SIZE | Invalid TP/SL size | | 11 | perp\_market\_config | EINVALID\_SIZE | Size == 0 | | 12 | perp\_market\_config | EORDER\_SIZE\_TOO\_LARGE | Price × size too large | ## cancel\_client\_order\_to\_subaccount | Error Code | Module | Error Name | When It Occurs | | ---------- | ----------------------- | ---------------------------------- | ------------------------------------------------------------------------------- | | 2 | pending\_order\_tracker | E\_MARKET\_NOT\_FOUND | Market not found in account's pending orders | | 3 | pending\_order\_tracker | E\_INVALID\_ORDER\_CLEANUP\_SIZE | Invalid order cleanup size (size mismatch or price×size mismatch) | | 4 | perp\_engine | EMARKET\_HALTED | Exchange is not open | | 5 | async\_matching\_engine | EINVALD\_WORK\_UNITS\_PER\_TRIGGER | Invalid work units (should not occur with DEFAULT\_WORK\_UNITS\_PER\_TRIGGER=5) | ## place\_bulk\_orders\_to\_subaccount | Error Code | Module | Error Name | When It Occurs | | ---------- | ----------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------- | | 1 | clearinghouse\_perp | EINVALID\_ARGUMENT | Prices/sizes length mismatch in get\_effective\_price\_and\_size | | 3 | clearinghouse\_perp | EINVALID\_SIZE\_IS\_TOO\_LARGE | Total size exceeds I64\_MAX | | 3 | dex\_accounts | ENOT\_SUBACCOUNT\_OWNER\_OR\_LACKS\_PERP\_TRADING\_PERMISSIONS | Signer lacks trading permissions | | 4 | perp\_market\_config | ESIZE\_NOT\_RESPECTING\_MIN\_SIZE | Any size \< min\_size | | 4 | perp\_engine | EMARKET\_HALTED | Exchange is not open | | 5 | clearinghouse\_perp | EINVALID\_PRICE\_IS\_TOO\_LARGE | Effective price exceeds I64\_MAX | | 5 | async\_matching\_engine | EINVALD\_WORK\_UNITS\_PER\_TRIGGER | Invalid work units | | 6 | perp\_market\_config | EPRICE\_NOT\_RESPECTING\_TICKER\_SIZE | Any price not multiple of ticker\_size | | 8 | dex\_accounts | ESUBACCOUNT\_IS\_NOT\_ACTIVE | Subaccount is inactive | | 10 | perp\_market\_config | EINVALID\_PRICE | Any price == 0 | | 11 | perp\_market\_config | EINVALID\_SIZE | Any size == 0 | | 12 | perp\_market\_config | EORDER\_SIZE\_TOO\_LARGE | Any price × size too large | | 13 | perp\_market\_config | EPRICE\_SIZES\_LENGTH\_MISMATCH | Prices length != sizes length | ## cancel\_bulk\_order\_to\_subaccount | Error Code | Module | Error Name | When It Occurs | | ---------- | ------------- | -------------------------------------------------------------- | -------------------------------- | | 3 | dex\_accounts | ENOT\_SUBACCOUNT\_OWNER\_OR\_LACKS\_PERP\_TRADING\_PERMISSIONS | Signer lacks trading permissions | | 4 | perp\_engine | EMARKET\_HALTED | Exchange is not open | | 8 | dex\_accounts | ESUBACCOUNT\_IS\_NOT\_ACTIVE | Subaccount is inactive | # Installation Source: https://docs.decibel.trade/typescript-sdk/installation Install the Decibel TypeScript SDK and its peer dependencies ## Install packages ```bash npm theme={null} npm install @decibeltrade/sdk @aptos-labs/ts-sdk zod ``` ```bash yarn theme={null} yarn add @decibeltrade/sdk @aptos-labs/ts-sdk zod ``` ```bash pnpm theme={null} pnpm add @decibeltrade/sdk @aptos-labs/ts-sdk zod ``` * Optional (TypeScript in Node): `@types/ws` ```bash npm theme={null} npm install -D @types/ws ``` ## Import and verify ```ts theme={null} import { DecibelReadDex, DecibelWriteDex, TESTNET_CONFIG, } from "@decibeltrade/sdk"; ``` The package includes ESM builds and TypeScript type definitions. # TypeScript SDK Overview Source: https://docs.decibel.trade/typescript-sdk/overview Decibel TypeScript SDK for reading market data and submitting transactions on Aptos ## What is the Decibel TypeScript SDK? The SDK provides a clean, typed interface to interact with Decibel on Aptos: Both `DecibelReadDex` and `DecibelWriteDex` require a [Node API token](/quickstart/node-api-key) for authentication. Without one, all requests return `401 Unauthorized: anonymous requests are not allowed`. Get yours from [Geomi](https://geomi.dev) before starting. **More SDKs coming soon.** Rust SDK is in development. For other languages, use the [REST API](/api-reference/rest/overview) or [WebSocket API](/api-reference/websocket/overview) directly. * Read operations: `DecibelReadDex` - query markets, depth, prices, trades, positions, orders, Trading Accounts, vaults. * Write operations: `DecibelWriteDex` - place/cancel orders, manage positions and Trading Accounts, vault operations, delegation. Install the SDK and required peer dependencies for Node or browser environments. Market data, account state, orders, positions, and historical data. Trading, position management, TP/SL, TWAP, Trading Accounts, and vault transactions. ## Quick start ### Read: market and account data ```ts theme={null} import { DecibelReadDex, TESTNET_CONFIG } from "@decibeltrade/sdk"; const read = new DecibelReadDex(TESTNET_CONFIG, { // Required: used to send Authorization: Bearer on node requests nodeApiKey: process.env.APTOS_NODE_API_KEY!, }); const markets = await read.markets.getAll(); const account = await read.accountOverview.getByAddr("0x...account"); ``` ### Write: submit transactions ```ts theme={null} import { DecibelWriteDex, TESTNET_CONFIG } from "@decibeltrade/sdk"; import { Ed25519Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk"; const account = new Ed25519Account({ privateKey: new Ed25519PrivateKey(process.env.PRIVATE_KEY!), }); const write = new DecibelWriteDex(TESTNET_CONFIG, account, { // Required: used to send Authorization: Bearer on node requests nodeApiKey: process.env.APTOS_NODE_API_KEY!, // Defaults: simulate before submit, fee payer enabled }); ``` ## When to use which * Use `DecibelReadDex` when you need market data, order/position history, or account state. No private keys required. * Use `DecibelWriteDex` for on-chain actions and trading. In browsers, avoid embedding private keys; prefer session keys or a wallet and pass `accountOverride` for specific calls. ## Related * Configuration and network presets: `MAINNET_CONFIG`, `TESTNET_CONFIG`, `LOCAL_CONFIG`, `DOCKER_CONFIG`, `NAMED_CONFIGS` * See REST and WebSocket topics in Quick Start for direct API access. # Read SDK Source: https://docs.decibel.trade/typescript-sdk/read-sdk Query market data, account state, and subscribe to real-time updates A [Node API token](/quickstart/node-api-key) is required. Without one, requests return `401 Unauthorized`. ## Purpose * Fetch market data (prices, depth, trades, candlesticks) and account views (orders, positions, Trading Accounts). * Works over REST and Aptos views. No signing or private keys required. ## When to use * Use for dashboards, analytics, and read-heavy server/frontend use cases. * Do not use for submitting transactions; use the Write SDK instead. ## Initialization ```ts theme={null} import { DecibelReadDex, TESTNET_CONFIG } from "@decibeltrade/sdk"; const read = new DecibelReadDex(TESTNET_CONFIG, { // Required: SDK will send Authorization: Bearer on fullnode requests nodeApiKey: process.env.APTOS_NODE_API_KEY!, onWsError: (e) => console.warn("WS error", e), // optional onChainFallback: ({ method }) => console.warn(`${method} fell back to chain views`), // optional }); ``` ## Main readers * Markets: `read.markets.getAll()`, `getAllSpot()`, `getByName()` * Spot asset contexts (24h stats + live mid per spot market): `read.spotAssetContexts.getAll()` * Prices: `read.marketPrices.getAll()`, `getByName()`, `subscribeByName()`, `subscribeAllSpotMids()` * Depth: `read.marketDepth.subscribeByName()`, `subscribeByAddr()`, `getAggregationSizes()` * Trades: `read.marketTrades.getByName()`, `getByAddr()`, `subscribeByName()`, `subscribeByAddr()` * Candlesticks: `read.candlesticks.getByName()`, `getByAddr()`, `subscribeByName()`, `subscribeByAddr()` * Accounts and orders: * `read.accountOverview.getByAddr()` * `read.userFees.getByAddr()` * `read.userOpenOrders.getByAddr()` / `read.userOrderHistory.getByAddr()` * `read.userOrders.getOrder()` (single order by `orderId` / `clientOrderId`) * `read.userBulkOrders.getByAddr()` / `getStatus()` / `getFills()` * `read.userPositions.getByAddr()` * `read.userTradeHistory.getByAddr()` * `read.userSubaccounts.getByAddr()` * Portfolio and leaderboard: * `read.portfolioChart.getByAddr()` * `read.leaderboard.getLeaderboard()` * Vaults and delegations: * `read.vaults.getUserOwnedVaults()` / `getVaults()` * `read.delegations.getAll()` * Funded First Trade: * `read.fundedFirstTrade.getEligibility()` / `getActiveTrial()` * `read.fundedFirstTrade.getTrialHistory()` / `getCampaignLocks()` (count-based pagination) * `read.fundedFirstTrade.subscribeByAddr()` * Chain views: `read.tokenBalance()`, `read.fungibleAssetMetadata()` (symbol/decimals/name for any fungible-asset address, e.g. `secondary_collateral` entries), `read.spotMarketAssets()` (a spot market's base/quote asset addresses — not exposed by `/markets`) ## Examples ### Markets ```ts theme={null} const markets = await read.markets.getAll(); const btc = await read.markets.getByName("BTC/USD"); // getAll() returns perp markets only. Pass includeSpot for both products // (narrow rows with isSpotMarket / isPerpMarket), or use getAllSpot() for // spot markets alone. On spot rows, sz_decimals is the base-asset decimals // and px_decimals the quote-asset decimals; perp-only fields are zeroed. import { isSpotMarket } from "@decibeltrade/sdk"; const allMarkets = await read.markets.getAll({ includeSpot: true }); const spotMarkets = await read.markets.getAllSpot(); ``` ### Spot on the shared order endpoints The order endpoints serve perp and spot on shared routes, with each row tagged `asset_type` (`"perp"` | `"spot"`). The account-scoped list readers (`userOpenOrders`, `userOrderHistory`, `userTradeHistory`, `userBulkOrders`, and `userBulkOrders.getFills`) default to `assetType: "perp"`, so existing perp consumers keep their exact pre-spot responses and pagination. Pass `"spot"` to scope to spot, or `"all"` to receive both products merged (server-side union pagination): ```ts theme={null} const perpOnly = await read.userOpenOrders.getByAddr({ subAddr }); const spotOnly = await read.userOrderHistory.getByAddr({ subAddr, assetType: "spot" }); const merged = await read.userOpenOrders.getByAddr({ subAddr, assetType: "all" }); const spotFills = await read.userTradeHistory.getByAddr({ subAddr, assetType: "spot" }); // Single order by orderId (perp + spot) or clientOrderId (perp only). // assetType defaults to unset here: the API checks perp, then spot. const order = await read.userOrders.getOrder({ subAddr, market, orderId: "42" }); // Bulk orders: placement status by sequence number, and fills const status = await read.userBulkOrders.getStatus({ subAddr, market, sequenceNumber: 7 }); const fills = await read.userBulkOrders.getFills({ subAddr, assetType: "all" }); ``` Spot trade rows also carry `fee_asset`, the FA address `fee_amount` is denominated in (base asset for the buyer, quote for the seller); it is absent on perp rows, where fees are implicitly USDC. ### Prices and candlesticks ```ts theme={null} const price = await read.marketPrices.getByName({ marketName: "BTC/USD" }); // Subscribe (unsubscribe by calling the returned function) const unsubscribe = read.marketPrices.subscribeByName("BTC/USD", (msg) => { console.log("Price update", msg); }); // Spot mids: one row per spot market, mid is null unless both book sides // have liquidity, last_trade_price is null until the first fill const unsubscribeSpot = read.marketPrices.subscribeAllSpotMids((msg) => { console.log("Spot mids", msg.mids); }); // Candlesticks import { CandlestickInterval } from "@decibeltrade/sdk"; const candles = await read.candlesticks.getByName({ marketName: "BTC/USD", interval: CandlestickInterval.OneMinute, startTime: Date.now() - 60 * 60 * 1000, endTime: Date.now(), }); ``` Name-based market-data methods (`candlesticks`, `marketDepth`, `marketTrades`) derive the market address from the name, which differs between perp and spot markets even when they share a name. They accept an optional `assetType` (`"perp"` default, or `"spot"`): ```ts theme={null} const spotCandles = await read.candlesticks.getByName({ marketName: "APT/USDC", assetType: "spot", interval: CandlestickInterval.OneMinute, startTime: Date.now() - 60 * 60 * 1000, endTime: Date.now(), }); const unsubTrades = read.marketTrades.subscribeByName("APT/USDC", onTrades, "spot"); const unsubDepth = read.marketDepth.subscribeByName("APT/USDC", 1, onDepth, "spot"); // If you already hold the market address, skip derivation entirely — the // address encodes the product, so no assetType is needed const tradesByAddr = await read.marketTrades.getByAddr({ marketAddr: market.market_addr }); const unsubTradesByAddr = read.marketTrades.subscribeByAddr(market.market_addr, onTrades); const unsubDepthByAddr = read.marketDepth.subscribeByAddr(market.market_addr, 1, onDepth); const byAddr = await read.candlesticks.getByAddr({ marketAddr: market.market_addr, interval: CandlestickInterval.OneMinute, startTime: Date.now() - 60 * 60 * 1000, endTime: Date.now(), }); const unsubCandles = read.candlesticks.subscribeByAddr( market.market_addr, CandlestickInterval.OneMinute, onCandle, ); ``` ### Account views ```ts theme={null} const ownerAddr = "0x...owner"; const subs = await read.userSubaccounts.getByAddr({ ownerAddr }); const overview = await read.accountOverview.getByAddr({ subAddr: subs[0].subaccount_addr }); // Spot inventory: PFS holdings with cost-basis PnL, open-order escrow // reservations, and lifetime spot metrics. Null for wallet-only owners; // absent on API versions that predate spot support. overview.spot?.positions; // [{ asset_addr, asset_symbol, amount, usd_value, entry_notional_usd, unrealized_pnl_usd }] overview.spot?.in_flight_orders; // escrow reserved by open spot orders overview.spot?.metrics; // cumulative volume / fees / realized PnL (USD) ``` ### User fees ```ts theme={null} const subAddr = "0x....subaccount"; const fees = await read.userFees.getByAddr({ subAddr }); // fees.user_taker_rate, fees.user_maker_rate, fees.fee_tier (decimals; 0.00045 = 0.045%) // fees.fee_schedule.tiers.vip[], fees.daily_user_volume[] ``` ### User positions ```ts theme={null} const subAddr = "0x....subaccount"; const stopPositions = read.userPositions.subscribeByAddr(subAddr, (data) => { data.positions.forEach((position) => { console.log("Position delta", position.market_name, position.open_size); }); }); // Stop streaming for this subaccount stopPositions(); ``` ## Notes * For raw REST/WS endpoints, see the API Reference tabs. # Write SDK Source: https://docs.decibel.trade/typescript-sdk/write-sdk Submit trades and manage Trading Accounts, positions, and vaults Two things before you start: a [Node API token](/quickstart/node-api-key) for authentication (without one, requests return `401 Unauthorized`) and an [API Wallet](/quickstart/typescript-starter-kit#create-api-wallet) to sign transactions. ## Purpose * Place/cancel orders (limit/market/stop, TP/SL, TWAP). * Place/cancel spot orders and spot bulk orders, and manage spot builder fees. * Manage collateral, Trading Accounts, delegations, and builder fees. * Create, fund, and manage vaults; place orders on behalf of a vault subaccount. ## When to use * Use when you need to submit transactions or manage trading state. * Avoid embedding private keys in browsers. Prefer: * Wallets/session keys and pass `accountOverride` for specific calls. * Server-side orchestration where secrets are controlled. ## Formatting price and size See the [formatting guide](../developer-hub/on-chain/overview/formatting-prices-sizes#convert-decimal-amount-to-chain-units) for converting UI values into chain units (e.g., `amountToChainUnits`). ## Initialization ```ts theme={null} import { DecibelWriteDex, TESTNET_CONFIG, GasPriceManager, } from "@decibeltrade/sdk"; import { Ed25519Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk"; const account = new Ed25519Account({ privateKey: new Ed25519PrivateKey(process.env.PRIVATE_KEY!), }); const gas = new GasPriceManager(TESTNET_CONFIG); await gas.initialize(); // optional but recommended const write = new DecibelWriteDex(TESTNET_CONFIG, account, { // Required: SDK will send Authorization: Bearer on fullnode requests nodeApiKey: process.env.APTOS_NODE_API_KEY!, gasPriceManager: gas, // speeds up building with cached gas skipSimulate: false, // default: simulate to estimate gas timeDeltaMs: 0, // see Advanced for clock skew handling }); ``` ## Function reference The sections below enumerate every callable helper exposed in `DecibelWriteDex` along with the argument types you should pass. All functions live on an instantiated `write` client unless otherwise noted. ### Utilities #### `sendSubaccountTx` Returns: `Promise` * `sendTx`: `(subaccountAddr: string) => Promise` (required) * `subaccountAddr`: `string` (optional) – defaults to primary subaccount Resolves the intended Trading Account before running the transaction. #### `withSubaccount` Returns: `Promise` * `fn`: `(subaccountAddr: string) => Promise` (required) * `subaccountAddr`: `string` (optional) – defaults to primary subaccount Utility to obtain the resolved Trading Account address inside arbitrary logic. ### Trading Accounts and Collateral #### `renameSubaccount` Returns: `Promise` * `subaccountAddress`: `string` (required) * `newName`: `string` (required) Renames a Trading Account. #### `createSubaccount` Returns: `Promise` No arguments. Creates a new Trading Account for the owner. #### `adminCreateSubaccount` Returns: `Promise` * `ownerAddress`: `string` (required) Admin-only helper that creates a new Trading Account for another wallet. #### `deposit` Returns: `Promise` * `amount`: `number` (required) – USDC amount in u64 base units * `subaccountAddr`: `string` (optional) – defaults to primary subaccount Deposits collateral to a Trading Account. #### `withdraw` Returns: `Promise` * `amount`: `number` (required) – USDC amount in u64 base units * `subaccountAddr`: `string` (optional) – defaults to primary subaccount Withdraws collateral from a Trading Account. #### `withdrawNonCollateral` Returns: `Promise` * `assetAddr`: `string` (required) * `amount`: `number` (required) – asset amount in u64 base units * `subaccountAddr`: `string` (optional) – defaults to primary subaccount Withdraws a non-collateral asset from a Trading Account. #### `configureUserSettingsForMarket` Returns: `Promise` * `marketAddr`: `string` (required) * `subaccountAddr`: `string` (required) * `isCross`: `boolean` (required) * `userLeverage`: `number` (required) Configures leverage and cross/isolated margin for a market. #### `buildDeactiveSubaccountTx` Returns: `Promise` * `subaccountAddr`: `string` (required) * `revokeAllDelegations`: `boolean` (required, defaults to `true`) * `signerAddress`: `AccountAddress` (required) Builds a transaction to deactivate a Trading Account. ```ts theme={null} const sub = write.getPrimarySubaccountAddress(write.account.accountAddress); // Deposit and then withdraw collateral (u64 base units) await write.deposit(1_000_000, sub); await write.withdraw(500_000, sub); // Example requested ``` ### Orders and matching #### `placeOrder` Returns: `Promise` * `marketName`: `string` (required) * `price`: `number` (required) – in chain units * `size`: `number` (required) – in chain units * `isBuy`: `boolean` (required) * `timeInForce`: `TimeInForce` (required) * `isReduceOnly`: `boolean` (required) * `clientOrderId`: `string` (optional) * `stopPrice`: `number` (optional) * `tpTriggerPrice`: `number` (optional) * `tpLimitPrice`: `number` (optional) * `slTriggerPrice`: `number` (optional) * `slLimitPrice`: `number` (optional) * `builderAddr`: `string` (optional) * `builderFee`: `number` (optional) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) * `tickSize`: `number` (optional) – auto-rounds prices to tick multiples Places a limit, market, or conditional order. #### `cancelOrder` Returns: `Promise` * `orderId`: `number | string` (required) * `marketName`: `string` (required if `marketAddr` not provided) * `marketAddr`: `string` (required if `marketName` not provided) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) Cancels an order by its ID. Selection rule: if you already have the market object address, prefer `marketAddr`; if you only have the market name (for example `BTC/USD`), use `marketName`. ```ts theme={null} await write.cancelOrder({ orderId: 12345, marketName: "BTC/USD", subaccountAddr: "0x...subaccount", // optional }); ``` ```ts theme={null} await write.cancelOrder({ orderId: 12345, marketAddr: "0x...market", subaccountAddr: "0x...subaccount", // optional }); ``` #### `cancelClientOrder` Returns: `Promise` * `clientOrderId`: `string` (required) * `marketName`: `string` (required) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) Cancels an order by client-provided ID. #### `cancelBulkOrder` Returns: `Promise` * `marketName`: `string` (required if `marketAddr` not provided) * `marketAddr`: `string` (required if `marketName` not provided) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) Cancels all bulk orders for a market on the selected Trading Account. Selection rule: if your flow already has a cached market address, use `marketAddr`; if your flow is market-name driven, use `marketName`. ```ts theme={null} await write.cancelBulkOrder({ marketName: "BTC/USD", subaccountAddr: "0x...subaccount", // optional }); ``` ```ts theme={null} await write.cancelBulkOrder({ marketAddr: "0x...market", subaccountAddr: "0x...subaccount", // optional }); ``` #### `triggerMatching` Returns: `Promise<{ success: boolean; transactionHash: string }>` * `marketAddr`: `string` (required) * `maxWorkUnit`: `number` (required) Manually advances matching for a market. #### `placeTwapOrder` Returns: `Promise` * `marketName`: `string` (required) * `size`: `number` (required) – in chain units * `isBuy`: `boolean` (required) * `isReduceOnly`: `boolean` (required) * `clientOrderId`: `string` (optional) * `twapFrequencySeconds`: `number` (required) * `twapDurationSeconds`: `number` (required) * `builderAddress`: `string` (optional) * `builderFees`: `number` (optional) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) Schedules recurring order slices over time. #### `cancelTwapOrder` Returns: `Promise` * `orderId`: `string` (required) * `marketAddr`: `string` (required) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) Stops a TWAP order stream. #### `updateOrder` Returns: `Promise` * `orderId`: `number | string` (required) * `marketAddr`: `string` (required) * `price`: `number` (required) – in chain units * `size`: `number` (required) – in chain units * `isBuy`: `boolean` (required) * `timeInForce`: `TimeInForce` (required) * `isReduceOnly`: `boolean` (required) * `tpTriggerPrice`: `number` (optional) * `tpLimitPrice`: `number` (optional) * `slTriggerPrice`: `number` (optional) * `slLimitPrice`: `number` (optional) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) Updates an existing order and optionally rewrites attached TP/SL values. **`placeOrder` argument shape** ```ts theme={null} type PlaceOrderArgs = { marketName: string; price: number; // already converted to on-chain units size: number; // on-chain base units isBuy: boolean; timeInForce: TimeInForce; isReduceOnly: boolean; clientOrderId?: string; stopPrice?: number; tpTriggerPrice?: number; tpLimitPrice?: number; slTriggerPrice?: number; slLimitPrice?: number; builderAddr?: string; builderFee?: number; subaccountAddr?: string; accountOverride?: Account; tickSize?: number; }; ``` ```ts theme={null} import { DecibelReadDex, TimeInForce } from "@decibeltrade/sdk"; // amountToChainUnits helper defined in docs/developer-hub/on-chain/overview/formatting-prices-sizes.mdx const read = new DecibelReadDex(write.config, { nodeApiKey: process.env.APTOS_NODE_API_KEY!, }); const market = await read.markets.getByName("BTC/USD"); if (!market) throw new Error("Market not found"); const orderResult = await write.placeOrder({ marketName: "BTC/USD", price: amountToChainUnits(45_000, market.px_decimals), size: amountToChainUnits(0.25, market.sz_decimals), isBuy: true, timeInForce: TimeInForce.GoodTillCanceled, isReduceOnly: false, clientOrderId: "dash-1234", builderAddr: "0x...builder", builderFee: 25, // 0.25% tickSize: market.tick_size, // optional price snapping to the market tick size }); if (orderResult.success && orderResult.orderId) { await write.cancelOrder({ orderId: orderResult.orderId, marketName: "BTC/USD", }); } await write.placeTwapOrder({ marketName: "BTC/USD", size: amountToChainUnits(2, market.sz_decimals), isBuy: true, isReduceOnly: false, twapFrequencySeconds: 30, twapDurationSeconds: 15 * 60, }); await write.cancelBulkOrder({ marketName: "BTC/USD", }); await write.updateOrder({ orderId: 12345, marketAddr: "0x...market", price: amountToChainUnits(45_100, market.px_decimals), size: amountToChainUnits(0.3, market.sz_decimals), isBuy: true, timeInForce: TimeInForce.GoodTillCanceled, isReduceOnly: false, }); ``` ### Spot trading All spot helpers are subaccount-scoped (defaulting to the primary Trading Account) and accept the market as `marketName` (address derived on the client) **or** `marketAddr` — the same selection rule as `cancelOrder`. Spot placement is asynchronous when funding requires a rate-limited CBS withdrawal: the transaction succeeds but the order is **queued**, not resting. `placeSpotOrder` reports this via `pendingCbs: true`; poll `read.userOrders.getOrder()` or `read.userOpenOrders.getByAddr({ assetType: "spot" })` for the real acknowledgment. #### `placeSpotOrder` Returns: `Promise` * `marketName`: `string` (required if `marketAddr` not provided) * `marketAddr`: `string` (required if `marketName` not provided) * `price`: `number` (required) – in chain units (quote decimals) * `size`: `number` (required) – in chain units (base decimals) * `isBuy`: `boolean` (required) * `timeInForce`: `TimeInForce` (required) – GTC, PostOnly, or IOC * `builderAddr`: `string` (optional) * `builderFee`: `number` (optional) – in basis points * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) * `tickSize`: `number` (optional) – auto-rounds the price to a tick multiple in the side-safe direction (buys round down, sells round up — the price is a limit/IOC bound, so rounding never crosses it) Places a spot limit order. Funds are sourced from the subaccount PFS first, then the remainder from CBS. #### `cancelSpotOrder` Returns: `Promise` * `orderId`: `number | string` (required) * `marketName` / `marketAddr`: `string` (one required) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) #### `placeSpotBulkOrder` Returns: `Promise` * `sequenceNumber`: `number` (required) – strictly increasing per market * `bidPrices` / `bidSizes` / `askPrices` / `askSizes`: `number[]` (required) – in chain units * `builderAddr`: `string` (optional), `builderFee`: `number` (optional, bps) * `marketName` / `marketAddr`: `string` (one required) * `subaccountAddr`: `string` (optional) Places (or replaces) a spot bulk order. Funds are sourced from the subaccount's PFS only — the transaction aborts if the PFS is short on either side. #### `cancelSpotBulkOrder` / `cancelSpotBulkOrderAtPriceLevel` Returns: `Promise` * `marketName` / `marketAddr`: `string` (one required) * `price`: `number`, `isBuy`: `boolean` (at-price-level variant only) * `subaccountAddr`: `string` (optional) #### `approveMaxSpotBuilderFee` / `revokeMaxSpotBuilderFee` Returns: `Promise` * `builderAddr`: `string` (required) – unlike perp, may be a subaccount **or** a primary wallet * `maxFee`: `number` (approve only, required) – in basis points * `subaccountAddr`: `string` (optional) #### `setHoldAsNonCollateral` Returns: `Promise` * `assetAddr`: `string` (required) – asset metadata object address * `hold`: `boolean` (required) * `subaccountAddr`: `string` (optional) When enabled, future deposits of the asset stay in the PFS (non-collateral) instead of routing into CBS collateral. Flag-only: existing balances are not moved. #### `processSpotPendingRequests` Returns: `Promise<{ success: boolean; transactionHash: string }>` * `marketName` / `marketAddr`: `string` (one required) * `maxFills`: `number` (required) Permissionless crank for pending async spot matching requests (spot analog of `triggerMatching`). ```ts theme={null} import { TimeInForce } from "@decibeltrade/sdk"; const spotMarket = await read.markets.getAllSpot().then( (ms) => ms.find((m) => m.market_name === "APT/USDC"), ); if (!spotMarket) throw new Error("Market not found"); const result = await write.placeSpotOrder({ marketName: "APT/USDC", price: amountToChainUnits(4.25, spotMarket.px_decimals), size: amountToChainUnits(100, spotMarket.sz_decimals), isBuy: true, timeInForce: TimeInForce.GoodTillCanceled, tickSize: spotMarket.tick_size, }); if (result.success && result.pendingCbs) { // Order queued behind a CBS withdrawal — poll for the acknowledgment } if (result.success && result.orderId) { await write.cancelSpotOrder({ orderId: result.orderId, marketName: "APT/USDC", }); } ``` ### Position TP/SL helpers #### `placeTpSlOrderForPosition` Returns: `Promise` * `marketAddr`: `string` (required) * `tpTriggerPrice`: `number` (optional) * `tpLimitPrice`: `number` (optional) * `tpSize`: `number` (optional) * `slTriggerPrice`: `number` (optional) * `slLimitPrice`: `number` (optional) * `slSize`: `number` (optional) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) * `tickSize`: `number` (optional) – auto-rounds prices to tick multiples Places both take-profit and stop-loss orders for a position. #### `updateTpOrderForPosition` Returns: `Promise` * `marketAddr`: `string` (required) * `prevOrderId`: `number | string` (required) * `tpTriggerPrice`: `number` (optional) * `tpLimitPrice`: `number` (optional) * `tpSize`: `number` (optional) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) * `tickSize`: `number` (optional) – auto-rounds prices to tick multiples Updates an existing take-profit order. #### `updateSlOrderForPosition` Returns: `Promise` * `marketAddr`: `string` (required) * `prevOrderId`: `number | string` (required) * `slTriggerPrice`: `number` (optional) * `slLimitPrice`: `number` (optional) * `slSize`: `number` (optional) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) * `tickSize`: `number` (optional) – auto-rounds prices to tick multiples Updates an existing stop-loss order. #### `cancelTpSlOrderForPosition` Returns: `Promise` * `marketAddr`: `string` (required) * `orderId`: `number | string` (required) * `subaccountAddr`: `string` (optional) * `accountOverride`: `Account` (optional) Cancels a TP/SL order. ```ts theme={null} import { DecibelReadDex } from "@decibeltrade/sdk"; const read = new DecibelReadDex(write.config, { nodeApiKey: process.env.APTOS_NODE_API_KEY!, }); const markets = await read.markets.getAll(); const market = markets.find((m) => m.market_addr === "0x...market"); if (!market) throw new Error("Market not found"); await write.placeTpSlOrderForPosition({ marketAddr: "0x...market", // amountToChainUnits helper defined in docs/developer-hub/on-chain/overview/formatting-prices-sizes.mdx tpTriggerPrice: amountToChainUnits(47_000, market.px_decimals), tpLimitPrice: amountToChainUnits(46_950, market.px_decimals), tpSize: amountToChainUnits(0.1, market.sz_decimals), slTriggerPrice: amountToChainUnits(43_000, market.px_decimals), slLimitPrice: amountToChainUnits(43_050, market.px_decimals), slSize: amountToChainUnits(0.1, market.sz_decimals), tickSize: market.tick_size, }); ``` ### Delegation and builder fees #### `delegateTradingToForSubaccount` Returns: `Promise` * `subaccountAddr`: `string` (required) * `accountToDelegateTo`: `string` (required) * `expirationTimestampSecs`: `number` (optional) Grants an operator permission to trade on behalf of the Trading Account. #### `revokeDelegation` Returns: `Promise` * `subaccountAddr`: `string` (optional) – defaults to primary subaccount * `accountToRevoke`: `string` (required) Removes trading delegation from an operator. #### `approveMaxBuilderFee` Returns: `Promise` * `builderAddr`: `string` (required) * `maxFee`: `number` (required) – in basis points * `subaccountAddr`: `string` (optional) – defaults to primary subaccount Approves a maximum builder fee for a Trading Account. #### `revokeMaxBuilderFee` Returns: `Promise` * `builderAddr`: `string` (required) * `subaccountAddr`: `string` (optional) – defaults to primary subaccount Revokes a previously approved builder fee. ```ts theme={null} await write.delegateTradingToForSubaccount({ subaccountAddr: "0x...subaccount", accountToDelegateTo: "0x...operator", }); await write.approveMaxBuilderFee({ builderAddr: "0x...builder", maxFee: 100, // 1% }); ``` ### Vault transactions Vault lifecycle helpers call the same on-chain entry functions documented in the [Vault Integration Guide](/developer-hub/guides/vaults). That guide uses only `DecibelWriteDex` / `DecibelReadDex` for TypeScript. On Aptos testnet, a full smoke flow needs about **210 USDC** in the contributor subaccount (`100_000_000` creation fee + `100_000_000` minimum `initialFunding` + `10_000_000` minimum follow-on `depositToVault`). See the funding table in the guide. End-to-end reference: `typescript/packages/e2e/src/vault-e2e.ts` — run `cd typescript/packages/e2e && pnpm start:vault-e2e` (`.env.example` lists required keys). **Gas Station (optional)** — Omit `gasStationApiKey` to have users pay gas with APT; `createVault`, `depositToVault`, `withdrawFromVault`, and `placeOrder` work as usual. If `gasStationApiKey` **is** set, custom Move calls (e.g. testnet `restricted_mint`) and manually signed `build*` transactions must use `buildTx` + `submitTx` instead of `aptos.transaction.build.simple`. See [Gas Station](/quickstart/gas-station) and vault guide steps 5 and 9. The `vault-e2e` script enables Gas Station on testnet for convenience only. `createVault`, `depositToVault`, and `withdrawFromVault` build, sign, and submit in one call. The `build*` helpers below return a `SimpleTransaction` for custom signing (for example fee-payer flows). Redemptions go through `withdrawFromVault`, which calls `dex_accounts_entry::redeem_from_vault`. There is no `build*` counterpart for redemption. #### `createVault` Returns: `Promise` Same parameters as `CreateVaultArgs` (see [type references](#type-references)), plus optional `subaccountAddr` and `accountOverride`. Submits `vault_api::create_and_fund_vault`. Parse the new vault address with `extractVaultAddressFromCreateTx`. #### `depositToVault` Returns: `Promise` * `vaultAddress`: `string` (required) * `amount`: `number` (required) — USDC in chain units (6 decimals) * `subaccountAddr`: `string` (required) — contributor's Trading Account #### `withdrawFromVault` Returns: `Promise` * `vaultAddress`: `string` (required) * `shares`: `number` (required) — share amount in chain units (minimum redemption is about `5_000_000` units, \~\$5 at 6 decimals on testnet) * `subaccountAddr`: `string` (optional) — defaults to primary subaccount Read `current_num_shares` before redeeming: `read.vaults.getUserPerformancesOnVaults({ ownerAddr: subaccountAddr })` — `ownerAddr` must be the contributor's Trading Account (subaccount), not the wallet address. All `build*` vault helpers accept `WithSignerAddress` (payload plus `signerAddress`). #### `buildCreateVaultTx` Returns: `Promise` * `contributionAssetType`: `string` (optional) * `vaultName`: `string` (required) * `vaultDescription`: `string` (required) * `vaultSocialLinks`: `string[]` (required) * `vaultShareSymbol`: `string` (required) * `vaultShareIconUri`: `string` (optional) * `vaultShareProjectUri`: `string` (optional) * `feeBps`: `number` (required) * `feeIntervalS`: `number` (required) * `contributionLockupDurationS`: `number` (required) * `initialFunding`: `number` (optional, default `0`) * `acceptsContributions`: `boolean` (optional, default `false`) * `delegateToCreator`: `boolean` (optional, default `false`) * `signerAddress`: `AccountAddress` (required) Builds a transaction to create a new vault. `createVault` applies the same defaults. #### `buildActivateVaultTx` Returns: `Promise` * `vaultAddress`: `string` (required) * `signerAddress`: `AccountAddress` (required) Builds a transaction to activate a vault. #### `buildDepositToVaultTx` Returns: `Promise` * `vaultAddress`: `string` (required) * `amount`: `number` (required) * `signerAddress`: `AccountAddress` (required) Builds a transaction to deposit funds into a vault. #### `buildDelegateDexActionsToTx` Returns: `Promise` * `vaultAddress`: `string` (required) * `accountToDelegateTo`: `string` (required) * `signerAddress`: `AccountAddress` (required) * `expirationTimestampSecs`: `number` (optional) Builds a transaction to delegate DEX actions for a vault. ```ts theme={null} const buildTx = await write.buildCreateVaultTx({ // Asset metadata object address (for example USDC metadata), not a Move type tag contributionAssetType: write.config.deployment.usdc, vaultName: "My Vault", vaultDescription: "Strategy description", vaultSocialLinks: [], vaultShareSymbol: "MVS", feeBps: 0, feeIntervalS: 0, contributionLockupDurationS: 0, initialFunding: 0, acceptsContributions: false, delegateToCreator: false, signerAddress: write.account.accountAddress, }); const depositTx = await write.buildDepositToVaultTx({ vaultAddress: "0x...vault", amount: 1_000_000, signerAddress: write.account.accountAddress, }); ``` ### Trading on behalf of a vault Vault trading is not a separate API. After the vault creator (or a delegate) is authorized via `delegateToCreator` or `buildDelegateDexActionsToTx`, call `placeOrder`, `cancelOrder`, TP/SL, or TWAP with `subaccountAddr` set to the **vault portfolio subaccount** — not your wallet's primary subaccount. Derive the vault subaccount from the vault object address: ```ts theme={null} import { AccountAddress } from "@aptos-labs/ts-sdk"; import { DecibelReadDex, getPrimarySubaccountAddr, TimeInForce, } from "@decibeltrade/sdk"; const vaultSubaccount = getPrimarySubaccountAddr( AccountAddress.fromString(vaultAddress), write.config.compatVersion, write.config.deployment.package, ); const read = new DecibelReadDex(write.config, { nodeApiKey: process.env.APTOS_NODE_API_KEY!, }); const markets = await read.markets.getAll(); const marketPrices = await read.marketPrices.getAll(); const market = markets.find((m) => m.market_name === "APT/USD"); if (!market) throw new Error("Market not found"); const midPx = marketPrices.find((p) => p.market === market.market_addr)?.mid_px; if (midPx == null) throw new Error("No mid price"); function amountToChainUnits(amount: number, decimals: number) { return Math.floor(amount * 10 ** decimals); } const orderResult = await write.placeOrder({ marketName: market.market_name, price: amountToChainUnits(midPx, market.px_decimals), size: market.min_size, isBuy: true, timeInForce: TimeInForce.ImmediateOrCancel, isReduceOnly: false, subaccountAddr: vaultSubaccount, tickSize: market.tick_size, }); if (orderResult.success) { console.log("Vault order placed:", orderResult.transactionHash); } else { console.error("Order failed:", orderResult.error); } ``` Use a market name that exists on your target network. The pattern above matches `typescript/packages/e2e/src/vault-e2e.ts` in this repository. That script runs **create → depositToVault → withdrawFromVault → delegate → placeOrder** on testnet. For the full vault launch walkthrough (mint, fund, create, delegate), see the [Vault Integration Guide](/developer-hub/guides/vaults). ### TWAP and notification helpers `placeTwapOrder`, `cancelTwapOrder`, and the readers exposed under `read.userActiveTwaps` bridge the trading + monitoring workflow. For notification rendering, reference the Rust trading API docs. ### Campaign rewards #### `claimCampaignReward` Returns: `Promise` * `campaignId`: `number` (required) Claims a reward allocation from the campaign package by numeric campaign ID. ### Funded First Trade #### `openFftTrial` / `claimFftUnlock` / `settleFftTrial` Returns: `Promise` * `campaignPackage`: `string` (required) * `campaignAddr`: `string` (required) * `owner`: `string` (`openFftTrial` / `claimFftUnlock`), `lockId`: `bigint` (`claimFftUnlock`), `trialId`: `number` (`settleFftTrial`) Session-key-friendly FFT entries: `openFftTrial` and `claimFftUnlock` accept a signer that is the owner or a `TradePerpsAllMarkets` delegate on the owner's primary subaccount; `settleFftTrial` is permissionless. Locking (`buildLockPayload` / `buildLockFromSubaccountPayload`) stays wallet-signed — those entries move the owner's own funds. ## Session keys and overrides All transaction helpers accept an `accountOverride` to sign with a different account (e.g., a session key) while the SDK was constructed with the primary account: ```ts theme={null} import { DecibelReadDex, TimeInForce } from "@decibeltrade/sdk"; import { Ed25519Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk"; const read = new DecibelReadDex(write.config, { nodeApiKey: process.env.APTOS_NODE_API_KEY!, }); const market = await read.markets.getByName("BTC/USD"); if (!market) throw new Error("Market not found"); const session = new Ed25519Account({ privateKey: new Ed25519PrivateKey(process.env.SESSION_PRIVATE_KEY!), }); await write.placeOrder({ marketName: "BTC/USD", price: amountToChainUnits(45_100, market.px_decimals), size: amountToChainUnits(0.5, market.sz_decimals), isBuy: true, timeInForce: TimeInForce.GoodTillCanceled, isReduceOnly: false, builderAddr: "0x...builder", builderFee: 25, // 0.25% accountOverride: session, }); ``` ## Type references ```ts theme={null} // RenameSubaccountArgs type RenameSubaccountArgs = { subaccountAddress: string; newName: string; }; // Utility used throughout builder helpers type WithSignerAddress = T & { signerAddress: AccountAddress; }; // CreateVaultArgs (see src/read/types.ts) type CreateVaultArgs = { contributionAssetType?: string; vaultName: string; vaultDescription: string; vaultSocialLinks: string[]; vaultShareSymbol: string; vaultShareIconUri?: string; vaultShareProjectUri?: string; feeBps: number; feeIntervalS: number; contributionLockupDurationS: number; initialFunding: number; acceptsContributions: boolean; delegateToCreator: boolean; }; type PlaceOrderResult = | { success: true; orderId: string | undefined; transactionHash: string; } | { success: false; error: string; }; type PlaceSpotOrderResult = | { success: true; orderId: string | undefined; // True when the order was queued behind a rate-limited CBS withdrawal // instead of reaching the book in this transaction. pendingCbs: boolean; transactionHash: string; } | { success: false; error: string; }; type ActivateVaultArgs = { vaultAddress: string; additionalFunding?: number; }; type DepositToVaultArgs = { vaultAddress: string; amount: number; }; type WithdrawFromVaultArgs = { vaultAddress: string; shares: number; }; ```