Skip to main content
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 the protocol-owned liquidity vault, see 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.

Part 1: Launch Your First Vault

Fund your account, create a vault on testnet, and activate it.

Part 2: How Vaults Work

Lifecycle, fees, shares, and parameters.

Part 3: Advanced Operations

Contributing, redeeming, querying, and delegation.

Part 1: Launch Your First Vault

You can also create and manage vaults through the Decibel UI without writing any code. Navigate to Accounts, then click the Vaults tab and “Create Vault.” This guide covers the programmatic approach.

1. Prerequisites

2. Install Dependencies

npm install @aptos-labs/ts-sdk

3. Set Up Your Script

Every code example in this guide uses these imports and constants:
import {
  Aptos,
  AptosConfig,
  Network,
  Account,
  Ed25519PrivateKey,
  AccountAddress,
  createObjectAddress,
} from "@aptos-labs/ts-sdk";

// Testnet contract address
const PACKAGE = "0x952535c3049e52f195f26798c2f1340d7dd5100edbe0f464e520a974d16fbe9f";

// Derive USDC metadata address from the package
const USDC_METADATA = createObjectAddress(
  AccountAddress.fromString(PACKAGE),
  new TextEncoder().encode("USDC"),
).toString();

const aptos = new Aptos(new AptosConfig({ network: Network.TESTNET }));

const account = Account.fromPrivateKey({
  privateKey: new Ed25519PrivateKey("0xYOUR_PRIVATE_KEY"),
});

4. Get Your Trading Account Address

Your Trading Account (subaccount) holds USDC collateral. Use the onchain view function to get its address:
const [primarySubaccount] = await aptos.view({
  payload: {
    function: `${PACKAGE}::dex_accounts::primary_subaccount`,
    typeArguments: [],
    functionArguments: [account.accountAddress.toString()],
  },
});
console.log("Primary subaccount:", primarySubaccount);
The primary subaccount is auto-created on your first deposit. You don’t need to create it manually.

5. Mint Testnet USDC

On testnet, you can mint USDC using the restricted_mint function (rate-limited per account). You need at least 100 USDC to fund a vault.
const tx = await aptos.transaction.build.simple({
  sender: account.accountAddress,
  data: {
    function: `${PACKAGE}::usdc::restricted_mint`,
    typeArguments: [],
    functionArguments: [
      500_000_000, // 500 USDC (6 decimals)
    ],
  },
});

const result = await aptos.signAndSubmitTransaction({
  signer: account,
  transaction: tx,
});
await aptos.waitForTransaction({ transactionHash: result.hash });
console.log("Minted USDC:", result.hash);

6. Deposit USDC to Your Trading Account

Move the USDC from your wallet into your Trading Account so it can be used as vault capital.
const tx = await aptos.transaction.build.simple({
  sender: account.accountAddress,
  data: {
    function: `${PACKAGE}::dex_accounts_entry::deposit_to_subaccount_at`,
    typeArguments: [],
    functionArguments: [
      primarySubaccount,  // Trading Account address from step 4
      USDC_METADATA,      // USDC metadata address
      200_000_000,        // 200 USDC (6 decimals)
    ],
  },
});

const result = await aptos.signAndSubmitTransaction({
  signer: account,
  transaction: tx,
});
await aptos.waitForTransaction({ transactionHash: result.hash });
console.log("Deposited USDC:", result.hash);

7. Create and Fund Your Vault

This creates a new vault and deposits your initial capital from your Trading Account. If you fund with at least $100, the vault activates automatically.
const tx = await aptos.transaction.build.simple({
  sender: account.accountAddress,
  data: {
    function: `${PACKAGE}::vault_api::create_and_fund_vault`,
    typeArguments: [],
    functionArguments: [
      primarySubaccount,        // funded_from_dex_subaccount
      USDC_METADATA,            // contribution_asset_type
      "My Trading Vault",       // vault_name
      "Algorithmic strategy",   // vault_description
      ["https://x.com/myvault", ""], // vault_social_links [xUrl, discordUrl]
      "MTV",                    // vault_share_symbol
      "",                       // vault_share_icon_uri
      "",                       // vault_share_project_uri
      500,                      // fee_bps (5% performance fee)
      2592000,                  // fee_interval_s (30 days in seconds)
      0,                        // contribution_lockup_duration_s (no lockup)
      100_000_000,              // initial_funding (100 USDC, 6 decimals)
      true,                     // accepts_contributions
      true,                     // delegate_to_creator
    ],
  },
});

const result = await aptos.signAndSubmitTransaction({
  signer: account,
  transaction: tx,
});
await aptos.waitForTransaction({ transactionHash: result.hash });
console.log("Vault created:", result.hash);
Setting delegate_to_creator to true automatically grants your account trading permissions on the vault. If you set it to false, you need to delegate separately later.
For full parameter details, see Create and Fund Vault.

8. Activate the Vault (if needed)

If your vault was funded with at least $100 at creation, it activates automatically. Otherwise, fund it to the minimum and then activate:
const tx = await aptos.transaction.build.simple({
  sender: account.accountAddress,
  data: {
    function: `${PACKAGE}::vault_api::activate_vault`,
    typeArguments: [],
    functionArguments: [
      vaultAddress, // Vault object address from the VaultCreatedEvent
    ],
  },
});

const result = await aptos.signAndSubmitTransaction({
  signer: account,
  transaction: tx,
});
await aptos.waitForTransaction({ transactionHash: result.hash });
console.log("Vault activated:", result.hash);
For full parameter details, see Activate Vault.

9. Delegate Trading (optional)

If you set delegate_to_creator to false during creation, or want to grant trading permissions to another account (e.g. a bot wallet):
const tx = await aptos.transaction.build.simple({
  sender: account.accountAddress,
  data: {
    function: `${PACKAGE}::vault_admin_api::delegate_dex_actions_to`,
    typeArguments: [],
    functionArguments: [
      vaultAddress,     // Vault object address
      botWalletAddress, // Address to delegate trading to
      null,             // No expiration (or Unix timestamp in seconds)
    ],
  },
});

const result = await aptos.signAndSubmitTransaction({
  signer: account,
  transaction: tx,
});
await aptos.waitForTransaction({ transactionHash: result.hash });
console.log("Delegated trading:", result.hash);
For full parameter details, see Delegate DEX Actions.

10. Place an Order as the Vault

With delegation set up, place orders on behalf of the vault using the same order placement flow. The vault’s pooled capital is used as margin.
Verify your vault is live. Browse to 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 the full contributor perspective.

Vault Lifecycle

PhaseWhat happens
CreationManager creates the vault, sets fee parameters, and deposits initial capital
Pre-activationVault exists but doesn’t accept contributions. Manager must fund it to the minimum ($100)
ActivationManager activates the vault (or it auto-activates if funded with >= $100 at creation). It can now accept outside contributions
Active tradingManager (or delegate) trades with pooled capital. Contributors can join or redeem
OngoingFees 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.
ParameterRange / Value
Performance fee0-10% (0-1000 bps)
Fee interval30-365 days
Min manager capitalLesser of 5% of vault NAV or $100,000
Min activation funding$100
Min contribution$10
Min redemption$5
Max contribution lockup0-7 days
Vault creation feeConfigurable (currently $0)

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 details.

Protocol Vault (DLP) vs User Vaults

Decibel runs one special vault, the Decibel Liquidity Provider (DLP), alongside user-created vaults. Both use the same onchain infrastructure.
DLP VaultUser Vaults
ManagerProtocol (automated)Any user
StrategyMarket makingManager’s discretion
Contribution lockup72 hours0-7 days (manager-configured)
Fee structure0%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. Contributions go through your Trading Account (subaccount).
const tx = await aptos.transaction.build.simple({
  sender: account.accountAddress,
  data: {
    function: `${PACKAGE}::dex_accounts_entry::contribute_to_vault`,
    typeArguments: [],
    functionArguments: [
      primarySubaccount, // Your Trading Account (Object<Subaccount>)
      vaultAddress,      // Vault address
      USDC_METADATA,     // USDC metadata address
      50_000_000,        // 50 USDC (6 decimals)
    ],
  },
});

const result = await aptos.signAndSubmitTransaction({
  signer: account,
  transaction: tx,
});
await aptos.waitForTransaction({ transactionHash: result.hash });
console.log("Contributed to vault:", result.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.

Redeeming Shares

To withdraw from a vault, redeem your share tokens for the underlying USDC. The minimum redemption is $5. The protocol may close up to 10% of positions per redemption at up to 2% slippage to free capital.
const tx = await aptos.transaction.build.simple({
  sender: account.accountAddress,
  data: {
    function: `${PACKAGE}::dex_accounts_entry::redeem_from_vault`,
    typeArguments: [],
    functionArguments: [
      primarySubaccount, // Your Trading Account (Object<Subaccount>)
      vaultAddress,      // Vault address
      10_000_000,        // Shares to redeem (6 decimals)
    ],
  },
});

const result = await aptos.signAndSubmitTransaction({
  signer: account,
  transaction: tx,
});
await aptos.waitForTransaction({ transactionHash: result.hash });
console.log("Redeemed from vault:", result.hash);
For full parameter details, see Redeem from Vault.

Querying Vault Data

Vault data is available through the REST API. See the vault endpoints for querying vault data like ownership, performance, and public vault listings.

Trading on Behalf of a Vault

The vault manager (or any delegated account) can place orders using the vault’s pooled capital:
  1. At creation: if delegate_to_creator is true, the vault creator automatically has trading permissions.
  2. After creation: the vault owner can delegate to additional accounts using delegate_dex_actions_to.
  3. Delegations can optionally have an expiration timestamp.
  4. The vault owner can revoke delegations at any time.
Once delegated, the account can place orders, manage positions, and execute trades using the vault’s capital. The same order types available to regular Trading Accounts (limit, market, TWAP, bulk) work for vaults.

What’s Next

1

Read the onchain reference

Full parameter docs for Create and Fund, Activate, Contribute, Redeem, and Delegate.
2

Understand vault fees and mechanics

See Vaults for Traders for the contributor perspective and Fees for the full fee breakdown.
3

Explore the DLP Vault

Learn about the protocol-owned liquidity vault and its backstop role on the DLP Vault page.
4

Build with the SDK

The TypeScript SDK provides high-level helpers for vault operations.