Skip to main content
Two things before you start: a Node API token for authentication (without one, requests return 401 Unauthorized) and an API Wallet to sign transactions.

Purpose

  • Place/cancel orders (limit/market/stop, TP/SL, TWAP).
  • 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 for converting UI values into chain units (e.g., amountToChainUnits).

Initialization

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 <YOUR_NODE_API_KEY> 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 tables below enumerate every callable helper exposed in DecibelWriteDex (plus the roundToTickSize utility) along with the argument types you should pass. All functions live on an instantiated write client unless otherwise noted.

Utilities

roundToTickSize

Returns: number
  • price: number (required) – price in chain units
  • tickSize: number (required) – tick size in chain units
Snaps prices to the nearest tick multiple.

sendSubaccountTx

Returns: Promise<CommittedTransactionResponse>
  • sendTx: (subaccountAddr: string) => Promise<CommittedTransactionResponse> (required)
  • subaccountAddr: string (optional) – defaults to primary subaccount
Resolves the intended Trading Account before running the transaction.

withSubaccount

Returns: Promise<T>
  • fn: (subaccountAddr: string) => Promise<T> (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<void>
  • subaccountAddress: string (required)
  • newName: string (required)
Renames a Trading Account.

createSubaccount

Returns: Promise<CommittedTransactionResponse> No arguments. Creates a new Trading Account for the owner.

deposit

Returns: Promise<CommittedTransactionResponse>
  • 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<CommittedTransactionResponse>
  • amount: number (required) – USDC amount in u64 base units
  • subaccountAddr: string (optional) – defaults to primary subaccount
Withdraws collateral from a Trading Account.

configureUserSettingsForMarket

Returns: Promise<CommittedTransactionResponse>
  • marketAddr: string (required)
  • subaccountAddr: string (required)
  • isCross: boolean (required)
  • userLeverage: number (required)
Configures leverage and cross/isolated margin for a market.

buildDeactiveSubaccountTx

Returns: Promise<SimpleTransaction>
  • subaccountAddr: string (required)
  • revokeAllDelegations: boolean (required, defaults to true)
  • signerAddress: AccountAddress (required)
Builds a transaction to deactivate a Trading Account.
import { getPrimarySubaccountAddr } from "@decibeltrade/sdk";

const sub = getPrimarySubaccountAddr(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<PlaceOrderResult>
  • 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<CommittedTransactionResponse>
  • 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.

cancelClientOrder

Returns: Promise<CommittedTransactionResponse>
  • clientOrderId: string (required)
  • marketName: string (required)
  • subaccountAddr: string (optional)
  • accountOverride: Account (optional)
Cancels an order by client-provided ID.

triggerMatching

Returns: Promise<{ success: boolean; transactionHash: string }>
  • marketAddr: string (required)
  • maxWorkUnit: number (required)
Manually advances matching for a market.

placeTwapOrder

Returns: Promise<PlaceOrderResult>
  • 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<CommittedTransactionResponse>
  • orderId: string (required)
  • marketAddr: string (required)
  • subaccountAddr: string (optional)
  • accountOverride: Account (optional)
Stops a TWAP order stream. placeOrder argument shape
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;
};
import { TimeInForce } from "@decibeltrade/sdk";
// amountToChainUnits helper defined in docs/developer-hub/on-chain/overview/formatting-prices-sizes.mdx

const orderResult = await write.placeOrder({
  marketName: "BTC-USD",
  price: amountToChainUnits(45_000),
  size: amountToChainUnits(0.25),
  isBuy: true,
  timeInForce: TimeInForce.GoodTillCanceled,
  isReduceOnly: false,
  clientOrderId: "dash-1234",
  builderAddr: "0x...builder",
  builderFee: 25, // 0.25 bps
  tickSize: 5, // optional snapping via roundToTickSize
});

if (orderResult.success && orderResult.orderId) {
  await write.cancelOrder({
    orderId: orderResult.orderId,
    marketName: "BTC-USD",
  });
}

await write.placeTwapOrder({
  marketName: "BTC-USD",
  size: amountToChainUnits(2),
  isBuy: true,
  isReduceOnly: false,
  twapFrequencySeconds: 30,
  twapDurationSeconds: 15 * 60,
});

Position TP/SL helpers

placeTpSlOrderForPosition

Returns: Promise<CommittedTransactionResponse>
  • 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<CommittedTransactionResponse>
  • marketAddr: string (required)
  • prevOrderId: number | string (required)
  • tpTriggerPrice: number (optional)
  • tpLimitPrice: number (optional)
  • tpSize: number (optional)
  • subaccountAddr: string (optional)
  • accountOverride: Account (optional)
Updates an existing take-profit order.

updateSlOrderForPosition

Returns: Promise<CommittedTransactionResponse>
  • marketAddr: string (required)
  • prevOrderId: number | string (required)
  • slTriggerPrice: number (optional)
  • slLimitPrice: number (optional)
  • slSize: number (optional)
  • subaccountAddr: string (optional)
  • accountOverride: Account (optional)
Updates an existing stop-loss order.

cancelTpSlOrderForPosition

Returns: Promise<CommittedTransactionResponse>
  • marketAddr: string (required)
  • orderId: number | string (required)
  • subaccountAddr: string (optional)
  • accountOverride: Account (optional)
Cancels a TP/SL order.
await write.placeTpSlOrderForPosition({
  marketAddr: "0x...market",
  // amountToChainUnits helper defined in docs/developer-hub/on-chain/overview/formatting-prices-sizes.mdx
  tpTriggerPrice: amountToChainUnits(47_000),
  tpLimitPrice: amountToChainUnits(46_950),
  tpSize: amountToChainUnits(0.1),
  slTriggerPrice: amountToChainUnits(43_000),
  slLimitPrice: amountToChainUnits(43_050),
  slSize: amountToChainUnits(0.1),
  tickSize: 5, // Example requested
});

Delegation and builder fees

delegateTradingToForSubaccount

Returns: Promise<CommittedTransactionResponse>
  • subaccountAddr: string (required)
  • accountToDelegateTo: string (required)
  • expirationTimestampSecs: number (optional)
Grants an operator permission to trade on behalf of the Trading Account.

revokeDelegation

Returns: Promise<CommittedTransactionResponse>
  • subaccountAddr: string (optional) – defaults to primary subaccount
  • accountToRevoke: string (required)
Removes trading delegation from an operator.

approveMaxBuilderFee

Returns: Promise<CommittedTransactionResponse>
  • 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<CommittedTransactionResponse>
  • builderAddr: string (required)
  • subaccountAddr: string (optional) – defaults to primary subaccount
Revokes a previously approved builder fee.
await write.delegateTradingToForSubaccount({
  subaccountAddr: sub,
  accountToDelegateTo: "0x...operator",
});

await write.approveMaxBuilderFee({
  builderAddr: "0x...builder",
  maxFee: 100, // 1 bps
});

Vault transactions

Vault lifecycle helpers call the same on-chain entry functions documented in the Vault Integration Guide. 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 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).
For redemptions, use withdrawFromVault (calls dex_accounts_entry::redeem_from_vault). Do not use buildWithdrawFromVaultTx for standard integrations — it targets a different entry function.

createVault

Returns: Promise<CommittedTransactionResponse> Same parameters as CreateVaultArgs (see type references), plus optional subaccountAddr and accountOverride. Submits vault_api::create_and_fund_vault. Parse the new vault address with extractVaultAddressFromCreateTx.

depositToVault

Returns: Promise<CommittedTransactionResponse>
  • vaultAddress: string (required)
  • amount: number (required) — USDC in chain units (6 decimals)
  • subaccountAddr: string (required) — contributor’s Trading Account

withdrawFromVault

Returns: Promise<CommittedTransactionResponse>
  • 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<T> (payload plus signerAddress).

buildCreateVaultTx

Returns: Promise<SimpleTransaction>
  • 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 (optional)
  • contributionLockupDurationS: number (optional)
  • initialFunding: number (required)
  • acceptsContributions: boolean (optional)
  • delegateToCreator: boolean (optional)
  • signerAddress: AccountAddress (required)
Builds a transaction to create a new vault.

buildActivateVaultTx

Returns: Promise<SimpleTransaction>
  • vaultAddress: string (required)
  • signerAddress: AccountAddress (required)
Builds a transaction to activate a vault.

buildDepositToVaultTx

Returns: Promise<SimpleTransaction>
  • vaultAddress: string (required)
  • amount: number (required)
  • signerAddress: AccountAddress (required)
Builds a transaction to deposit funds into a vault.

buildWithdrawFromVaultTx

Returns: Promise<SimpleTransaction>
  • vaultAddress: string (required)
  • shares: number (required)
  • signerAddress: AccountAddress (required)
Builds a transaction to withdraw shares from a vault.

buildDelegateDexActionsToTx

Returns: Promise<SimpleTransaction>
  • vaultAddress: string (required)
  • accountToDelegateTo: string (required)
  • signerAddress: AccountAddress (required)
  • expirationTimestampSecs: number (optional)
Builds a transaction to delegate DEX actions for a vault.
const buildTx = await write.buildCreateVaultTx({
  contributionAssetType: "0x1::fungible_asset::Metadata",
  vaultName: "My Vault",
  vaultDescription: "Strategy description",
  vaultSocialLinks: [],
  vaultShareSymbol: "MVS",
  feeBps: 0,
  initialFunding: 0,
  signerAddress: account.accountAddress,
});

const depositTx = await write.buildDepositToVaultTx({
  vaultAddress: "0x...vault",
  amount: 1_000_000,
  signerAddress: 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:
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.

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.

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:
import { Ed25519Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

const session = new Ed25519Account({
  privateKey: new Ed25519PrivateKey(process.env.SESSION_PRIVATE_KEY!),
});

await write.placeOrder({
  marketName: "BTC-USD",
  price: amountToChainUnits(45_100),
  size: amountToChainUnits(0.5),
  isBuy: true,
  timeInForce: TimeInForce.GoodTillCanceled,
  isReduceOnly: false,
  builderAddr: "0x...builder",
  builderFee: 25,
  accountOverride: session,
});

Type references

// RenameSubaccountArgs
type RenameSubaccountArgs = {
  subaccountAddress: string;
  newName: string;
};

// Utility used throughout builder helpers
type WithSignerAddress<T> = 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 ActivateVaultArgs = {
  vaultAddress: string;
  additionalFunding?: number;
};

type DepositToVaultArgs = {
  vaultAddress: string;
  amount: number;
};

type WithdrawFromVaultArgs = {
  vaultAddress: string;
  shares: number;
};