# Introduction

The DeFi engine for financial applications.

## Overview

Veda is a DeFi vault primitive, which is a mechanism for pricing, accounting, securing, optimizing, and automating capital. Veda sits as a layer above DeFi protocols (lending, DEXs, staking), packaging the best of DeFi into non-custodial, trust-minimized, and composable products. Veda lets fintechs, asset issuers, exchanges, chains, wallets, and applications build enterprise-grade DeFi yield products without reinventing complex smart contract and offchain infrastructure.

Veda is the only vault infrastructure built to be multi-chain and multi-protocol, so partners can access the best yields across chains without being locked into any single protocol. It handles the complexity of cross-chain operations, yield optimization, and risk mitigation, lowering the barrier to onchain finance for both consumer and institutional participants. Protocols that integrate Veda can onboard users with transparent, real-time safeguards.

Veda's track record in the vault and curation category:

* Recognized as the largest vault provider in DeFi, operating at billion-dollar scale for years with zero security incidents.
* Longest-running and largest general-purpose vault company in DeFi history.
* Developed the BoringVault, the most widely used vault standard across DeFi.
* Onboarded the first vault token, eBTC, onto Aave's main market.
* Powering Kraken DeFi Earn, EtherFi Liquid Vaults, Lido Earn, and distributed through Binance Web3 wallet and Bybit Web3 wallet.

## The Problem: DeFi is Complex, Fragmented, & Inefficient

### Friction in Accessing Yield

DeFi offers powerful financial tools, but accessing and optimizing yield remains unnecessarily complex:

* The same asset exists in multiple forms (staked, restaked, wrapped), each with different risks, liquidity, and utilities.
* Users must navigate multiple chains, manually bridging assets and acquiring the correct gas tokens.
* Every protocol has different interfaces, terminologies, and operational risks, creating an overwhelming experience.
* The optimal strategy to earn on your assets varies with market conditions and is increasing in complexity.
* Each business has its own compliance framework for offering DeFi products to its userbase.

### Unclear and Evolving Risk

Users are forced to assess smart contract and market risks manually, without clear, standardized disclosures:

* Risks evolve as protocols upgrade, making continuous risk assessment impractical.
* There are no automated protections, exposing users to systemic failures and exploits.
* Market conditions are unpredictable requiring vigilant monitoring on factors like liquidity, peg stability, price, protocol health, etc.

### Bootstrapping New Ecosystems

New ecosystems, whether that ecosystem revolves around a chain or an asset, require a critical mass of capital to function efficiently:

* Without deep liquidity, new ecosystems lack efficient markets, composability, and sustainable network effects.
* Vault-based liquidity solutions have proven effective, but teams shouldn't be forced to develop their own vault solution to kickstart this flywheel. Instead, they should be able to build on generalized vault infrastructure that is both flexible and secure.

### Capital Retention and Liquidity Efficiency

Crypto applications and chains don’t just struggle to attract liquidity. They also struggle to retain it and make it productive:

* **Liquidity Mining is Unsustainable:** Incentive programs attract short-term capital, but capital leaves once rewards dry up and there is no longer an easy way to earn.
* **Liquidity Sits Idle:** Staked or bridged liquidity is often underutilized instead of being natively productive within the ecosystem. This is also true for DeFi applications where lack of time or too much complexity relegates users to adopt lazy positions that reduce a protocol’s capital efficiency.
* **Capital Fragmentation:** For asset issuers and multichain protocols, assets are spread across multiple chains and protocols, making it difficult to aggregate liquidity and sustain deep markets.

## Veda's Approach: A DeFi Vault Primitive

<figure><img src="/files/2LPhZAozajJrZNDuysUT" alt=""><figcaption></figcaption></figure>

### What Is a DeFi Vault Primitive?

A DeFi vault primitive is foundational infrastructure that allows developers to easily onboard capital, mitigate risk, and optimize ecosystem liquidity. Veda’s BoringVault anchors this process by providing:

* **Standardized Pricing & Accounting:** Tracks user balances and vault share valuations in real time.
* **Adaptive Allocation:** Dynamically allocates capital across different yield strategies.
* **Automated Optimization:** Continuously rebalances for optimal risk-adjusted profile.
* **Rapid Iteration:** Launch new vaults or update strategies in as little as 48 hours.

### Core Differentiators

* **Protocol-, Asset-, and Chain-Agnostic:** Works across multiple blockchains including EVM, SVM, and even MoveVM, and integrates with many DeFi protocols.
* **Arbitrarily Complex Strategies:** Offchain logic combined with Veda's modular architecture allows vault curators/strategists to run any onchain yield strategy and even multiple strategies within a single vault
* **Verifiable Constraints:** Vault operations are constrained to a whitelisted set of actions that are viewable onchain.
* **Non-Custodial:** User funds reside in audited smart contracts, eliminating the need for centralized custody. Unlike centralized yield products, all Veda vault assets are fully on-chain and verifiable. Users can see their assets at any time through block explorers—even if the distribution partner goes offline.
* **Composable:** Easily integrates with other DeFi primitives like lending markets, DEXs, and yield trading protocols to build new financial applications. Veda vault shares are the first vault tokens ever onboarded as collateral on Aave’s main market.


# Architecture & Flow of Funds

The BoringVault is a secure, flexible framework for building enterprise-grade DeFi products.

## **Overview**

Veda's BoringVault is built on a modular architecture with minimal core contract logic (\~100 lines of code, hence "boring"). Rather than embedding complex functionality into a single contract, the system delegates specific responsibilities to purpose-built external modules. This separation enhances security - each module can be audited, upgraded, and restricted independently while keeping the core vault contract simple and predictable.

<figure><img src="/files/7hc1XPQI72hOMvovjngx" alt=""><figcaption></figcaption></figure>

The **BoringVault** is the central contract where all vault funds are custodied. It minimizes internal logic by delegating responsibilities to purpose-built external modules. The **Teller** handles deposits and withdrawals — minting shares on deposit at the exchange rate provided by the **Accountant**, enforcing share lock periods to protect against MEV, and burning shares on withdrawal. The Accountant publishes the vault's exchange rate with onchain safety checks that limit update frequency and constrain rate movements.

Strategy execution is governed by the **Manager**, which stores all permitted operations in a Merkle tree and verifies each rebalance action against it, ensuring only pre-authorized protocol interactions can occur. The **DecoderAndSanitizer** provides an additional layer of validation by decoding and checking calldata for every external call the vault makes. An optional **Hook** module can enforce custom logic before share transfers, enabling compliance features like address whitelisting or transfer restrictions.

For withdrawals, the **BoringQueue** implements a time-delayed, solver-based process: users submit a withdrawal request, and after a configurable maturity period, third-party solvers fulfill it by delivering the underlying assets. The BoringQueue serves as the standard withdrawal method and as a fallback when instant withdrawal buffers have insufficient liquidity.

## Flow of Funds

The following describes the lifecycle of assets through a Veda vault — from deposit through strategy deployment to withdrawal. At every stage, funds remain onchain: held in the BoringVault contract, deployed into DeFi protocol positions managed by the vault, or in transit through the withdrawal process.

1. **Deposit** — The user deposits assets (e.g., USDC or USDT) through the Teller and receives vault share tokens (e.g., vUSD) in return. The Teller retrieves the current exchange rate from the Accountant to determine how many shares to mint.
2. **Vault custody** — Deposited assets are held in the BoringVault contract awaiting strategy deployment.
3. **Strategy deployment** — The Curator submits a rebalance message with a Merkle proof to the Manager. The Manager verifies the operation against the Merkle tree whitelist — which encodes every permitted target contract, function call, and parameter — and, if valid, deploys the vault's assets into approved DeFi protocols such as Aave, Morpho, Euler, and others.
4. **Withdrawal** — When a user wants to exit, they submit a withdrawal request to the Withdrawal Queue, sending their vault shares and receiving the underlying assets in return. Separating the withdrawal logic from the core vault contract provides additional security isolation — the BoringVault itself never needs to implement complex exit logic.
5. **Exchange rate updates** — The Oracle provides pricing information to the Accountant, which calculates and updates the vault's exchange rate to reflect earned yield. Onchain safety checks limit update frequency and constrain how much the rate can change between updates.


# Core Components

#### BoringVault

The central contract where users deposit assets and where all vault funds are custodied. BoringVault minimizes internal logic by delegating tasks to external modules. It holds the assets, mints and burns share tokens, and executes management calls — but the rules governing *how* and *when* those actions happen are enforced by the surrounding modules.

#### Teller

The Teller handles user-facing interactions for depositing into and withdrawing from the vault. When a user deposits, the Teller retrieves the current exchange rate from the Accountant, calculates the shares to mint, and coordinates the transfer of assets into the BoringVault. On withdrawal, it burns shares and returns the corresponding assets.

The Teller enforces share lock periods after deposit to protect against arbitrage and MEV exploitation. During the lock period, shares cannot be transferred or redeemed. Certain vault configurations also allow the Teller to refund deposits if needed, providing an additional safety mechanism.

Vault deployments may use specialized Teller variants depending on the vault's configuration — for example, `TellerWithYieldStreaming` for vaults that stream yield gradually over time, or `TellerWithBuffer` for vaults with instant withdrawal capabilities.

#### Accountant

The Accountant calculates and publishes the exchange rate between vault shares and the underlying assets. Exchange rates are updated offchain and pushed onchain, with built-in safety checks: rate limiting restricts how frequently updates can occur, and deviation bounds constrain how much the rate can move relative to the previous value. If an update falls outside acceptable bounds, the Accountant can pause rate updates to safeguard against volatile market conditions or oracle manipulation.

For vaults with yield streaming enabled, the `AccountantWithYieldStreaming` variant smooths rate changes over time rather than applying them in discrete jumps, providing a more predictable return profile for depositors.

#### Manager

The Manager controls which strategies the vault can execute during rebalancing. It stores all permitted operations in a Merkle tree, where each leaf encodes a specific allowed action: the target contract address, the function to call, and the acceptable parameter values. When the vault executes a strategy, the Manager verifies the operation against its Merkle proof, ensuring that only pre-authorized actions can be performed.

The system supports per-strategist Merkle trees, enabling granular access control. A main strategist may have broad permissions to rebalance across many protocols, while specialized or automated accounts can operate under tighter constraints.

#### Hook

An optional module that triggers custom logic before share transfers occur. Hooks can enforce transfer restrictions, implement whitelisting requirements, lock shares to prevent transfers, or execute other compliance-related checks at the smart contract level.

Common use cases include restricting deposits to approved addresses, preventing share transfers during certain conditions, and implementing regulatory compliance logic directly onchain.

#### DecoderAndSanitizer

When the vault interacts with external DeFi protocols, the DecoderAndSanitizer decodes and validates the calldata for each operation. It ensures that only safe and intended interactions are performed — verifying target addresses, function selectors, and parameter values before the vault executes any external call. Each integrated protocol has its own DecoderAndSanitizer implementation tailored to that protocol's interface.

#### BoringQueue

The BoringQueue (`BoringOnChainQueue`) implements time-delayed, solver-based withdrawals. When a user submits a withdrawal request, their shares are transferred to the queue and the request enters a maturity period. After maturity, third-party solvers can fulfill the request by providing the underlying assets to the user in exchange for the vault shares.

The BoringQueue serves as the standard withdrawal method for vaults without instant withdrawals enabled, and as a fallback when instant withdrawal buffers have insufficient liquidity. Key parameters — including the maturity period, solver deadline window, and discount range — are configurable per asset. Users can cancel unfulfilled requests at any time to reclaim their shares.


# Fees

## Fee Parameters

Veda supports both **platform fees** and **performance fees**.

A **platform fee** is charged as an annualized percentage of the vaults assets, allowing fees to accrue based on assets held in the vault regardless of the yield generated.

A **performance fee** is charged as a percentage of rewards generated by the vault. By default, the onchain performance fee parameter is applied relative to the user’s realized rewards after fees (net rewards).

If you want to express the performance fee using the commonly used gross rewards convention, adjust the parameter as follows:

`onchainFeeParameter = grossFeeRate / (1 - grossFeeRate)`

For example, a 25% fee on gross rewards corresponds to a 33.33% onchain fee parameter.


# Integrations


# Deposits & Withdrawals Overview

This page explains how funds flow into and out of Veda vaults at a high level. All deposits and withdrawals are executed onchain through Veda's smart contracts — your assets are always held in the BoringVault contract or in the DeFi positions it manages, never in an offchain system.

### Deposits

#### How Deposits Work

When you deposit into a Veda vault, you interact with two contracts: the **BoringVault** (which will hold your assets) and the **Teller** (which processes the deposit and mints your shares).

The flow is:

1. **Approve** — You approve the BoringVault contract to spend your tokens. (Note: the approval target is the BoringVault address, not the Teller.)
2. **Deposit** — You call `teller.deposit()` with your chosen asset and amount. The Teller retrieves the current exchange rate from the Accountant, calculates how many vault shares to mint, and coordinates the transfer.
3. **Receive shares** — Your tokens move into the BoringVault, and vault shares are minted to your wallet. These shares represent your proportional claim on the vault's assets plus any accrued yield.

For tokens that support EIP-2612 permits, you can combine the approval and deposit into a single transaction using `teller.depositWithPermit()`, saving gas and simplifying the user experience.

#### After You Deposit

**Share lock period** — After depositing, your shares may be locked for a configurable period (depending on the vault). During this time, shares cannot be transferred or redeemed. This protects the vault and other depositors against arbitrage and MEV exploitation.

**Automatic buffer routing** — In vaults with instant withdrawals enabled, your deposited assets may be automatically routed into yield-generating positions (such as Aave V3 lending pools) within the same transaction. This is handled by onchain BufferHelper contracts that generate the necessary instructions — importantly, BufferHelpers never hold funds themselves.

**Slippage protection** — The `minimumMint` parameter on deposits protects you from receiving fewer shares than expected if the exchange rate changes between when you prepare your transaction and when it executes. A 0.1% tolerance is recommended for most use cases.

#### Checking Deposit Eligibility

Before depositing, you can verify that an asset is supported by checking `teller.assetData(tokenAddress)` to confirm `allowDeposits` is true, or by calling `lens.checkUserDeposit()` for a comprehensive eligibility check.

***

### Withdrawals

Veda vaults support two withdrawal methods. Which method to use depends on the vault's configuration and current liquidity conditions.

| Condition                                                             | Recommended Method         |
| --------------------------------------------------------------------- | -------------------------- |
| Vault has instant withdrawals enabled AND sufficient buffer liquidity | **Instant Withdrawal**     |
| Vault uses standard configuration OR buffer liquidity is insufficient | **BoringQueue Withdrawal** |

#### Instant Withdrawals

For vaults with instant withdrawals enabled, you can withdraw funds immediately in a single atomic transaction — no waiting for solvers or settlement periods.

When you call `teller.withdraw()`, the vault checks the available buffer liquidity for your requested asset. If sufficient liquidity exists, the transaction completes atomically: your shares are burned, the buffer position is exited if needed, and the underlying assets arrive in your wallet within the same transaction.

You can check available instant liquidity before attempting a withdrawal using the **BufferLens** contract, which reports the withdrawable amount for each asset based on the current buffer configuration.

If your withdrawal amount exceeds available buffer liquidity, use the BoringQueue method instead.

#### BoringQueue Withdrawals

The BoringQueue is the standard withdrawal method for vaults without instant withdrawals, and serves as the fallback when instant withdrawal buffers don't have enough liquidity.

BoringQueue withdrawals are a two-step process:

1. **Request** — You approve the BoringQueue contract to spend your vault shares, then call `queue.requestOnChainWithdraw()` specifying the asset you want to receive, the number of shares to redeem, a discount (in basis points), and a deadline window. Your shares transfer to the queue.
2. **Fulfillment** — After a maturity period (typically \~1 hour, configurable per asset), third-party solvers can fulfill your request. The solver provides the underlying assets directly to your wallet in exchange for the vault shares held in the queue.

You don't need to take any action after submitting your request — once a solver fulfills it, assets are sent directly to you. If the request is not fulfilled within the deadline window, it expires and you can cancel to reclaim your shares.

**Key parameters** — You can query `queue.withdrawAssets(assetAddress)` to get the recommended values for each asset, including the maturity period, minimum deadline, allowed discount range, and minimum share amount.

**Cancellation** — You can cancel a pending withdrawal request at any time before it's fulfilled by calling `queue.cancelOnChainWithdraw()`, which returns your shares to your wallet.

## Compatibility

**Wallet & Provider Compatibility** — Veda's deposit and withdrawal contracts use standard ERC-20 approve/transfer patterns and are compatible with any wallet or web3 provider that supports EVM transactions, including Privy, MetaMask, WalletConnect, Coinbase Wallet, Safe multisig, RainbowKit, and libraries like wagmi and viem.


# Veda Curation Services

### Introduction: The Need for Curation

Veda vaults are programmable, onchain DeFi solutions that enable multichain, multiasset, and multiprotocol yield strategies. The vault infrastructure is operated by a vault curator. The curator determines the vault’s active strategies and protocol allocations, navigating a 24/7 market while optimizing for competitive, risk-adjusted yield.

Veda Curation Services bridge the gap between complex onchain mechanics and the institutional need for safety, transparency, compliance, and performance.

### What is Veda Curation?

Veda Curation is a managed service where our team acts as the curator or strategy manager for your Veda vaults. Enterprises that integrate Veda Curation don’t have to manually monitor liquidation prices, gas costs, or protocol upgrades.

Our curation services apply Veda's DeFi expertise to your vault, a hands-off way to generate yield while managing key risks.

The Veda Curation Team:

* Monitors protocols: Continuous auditing of integrated DeFi protocols.
* Optimizes liquidity: Managing leverage, asset weightings, and protocol exposure to limit risk and ensure rapid redemptions.
* Rebalances vaults: Shifting liquidity across protocols and chains to capture yield while mitigating risk.

### High-Level Benefits

**Accelerated Time-to-Market**

Building an internal DeFi research and operations team takes years of effort and market experience. Veda Curation lets partners launch a sophisticated "Earn" product in weeks instead of months or years.

**Institutional-Grade Yield**

Veda’s curation strategies have historically outperformed standard market benchmarks. Through active management and multichain strategies, Veda Curation aims to deliver a 200–400 bps premium over passive "set-and-forget" alternatives.

**Advanced Risk Mitigation**

Yield is never "risk-free." Veda Curators focus on Risk Isolation, ensuring protocol-specific failures or liquidity crunches are managed through diversification and automated safety triggers.

### Full-Service Curation, From Start to Finish:

* Strategy Design: We work with your team to define a risk profile (e.g., Conservative, Market Neutral, or Aggressive Growth).
* Operational Automation: Full management of manual rebalancing and complex crosschain strategy execution, including basis trades.
* Reporting & Transparency: Access to Veda’s Command Center, providing real-time data on performance, protocol health, and curation actions.
* GTM Advisory: Support for your marketing and compliance teams to help translate complex DeFi strategies into clear value propositions for your customers.
* Index Products: Veda’s architecture supports index products in any category.

### Example Use Cases

* For Centralized Exchanges (CEXs): Offer native, white-label "Earn" products that differentiate your platform from the competition, without the overhead of a 24/7 DeFi trading desk.
* For Neobanks & Fintechs: Let users activate idle balances with institutional-grade stablecoin yield from the best of DeFi to encourage customer retention and attract new users.
* For Asset Managers & Hedge Funds: Integrate Veda as a "Vault-as-a-Service" partner to execute sophisticated onchain strategies with professional oversight.

<br>


# API

Programmatic access to Veda vaults.

The Veda API is the programmatic surface for interacting with Veda vaults outside of the [Veda Console](https://console.veda.tech). It exposes the same primitives that power Veda's first-party products — rebalancing, position data, fees, and accounting — to partners building automation, dashboards, custom strategist tooling, and back-office integrations.

**Base URL:** `https://api.veda.tech`

**Authentication:** Bearer token using an API key created in the [Veda Console](https://console.veda.tech).

**OpenAPI / Swagger:** [api.veda.tech/docs](https://api.veda.tech/docs)

## What's here

| Page                                                                  | Purpose                                                                 |
| --------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| [Quick Start](/api/quick-start)                                       | Create an API key in the console and make your first authenticated call |
| [Vaults](/api/vaults)                                                 | List your tenant's vaults; inspect roots set on a specific vault        |
| [Policy Manager & Merkle Trees](/api/policy-manager-and-merkle-trees) | How vault permissioning works; fetch a merkle tree by root hash         |
| [Transaction Builder](/api/transaction-builder)                       | Discover vault actions and build rebalance calldata                     |
| [API Reference](/api/api-reference)                                   | Full endpoint reference via the OpenAPI spec                            |
| [Change Log](/api/change-log)                                         | What's new, what's deprecated, examples, rate limits                    |

## When to use the API

The API is the right choice when you need to:

* **Automate rebalancing** — write a script or scheduled job that builds and submits rebalance transactions for a vault you operate as a strategist
* **Build a custom dashboard** — surface vault state inside your own product

For everything the hosted API serves, the underlying data is also reconstructible directly from chain. Many partners run both: the API for the fast path, and their own indexer for whatever the API doesn't expose.

## Capabilities

* **Protocol-, asset-, and chain-agnostic** — the same endpoints work across every chain Veda supports
* **Verifiable** — `encoded_tx_data` is calldata you submit yourself from your strategist address; the API never holds keys or signs
* **Simulated by default** — every build is dry-run against Tenderly before returning, so you can catch reverts before broadcasting
* **Composable** — batch multiple actions into a single atomic transaction with `execute-multiple`

## Getting access

API keys are provisioned per partner. If you don't already have a Veda Console account for your team:

1. Reach out to your Veda contact
2. Once your account is provisioned, sign in to [console.veda.tech](https://console.veda.tech)
3. Follow [Quick Start](/api/quick-start) to create your first key


# Quick Start

The shortest path from "I have a Veda Console account" to "I'm making authenticated API calls." Five minutes, no SDK required.

## Prerequisites

* A [Veda Console](https://console.veda.tech) account with API key access
* A terminal with `curl`, or a runtime of your choice (Python, Node, anything that can send HTTP)

If you don't yet have a console account, see [Getting access](/api#getting-access).

## 1. Create an API key

API keys are created and managed in the Veda Console.

1. Sign in to [console.veda.tech](https://console.veda.tech)
2. Go to **Settings → API keys**
3. Click **Create API key**
4. Give the key a description (e.g. `mainnet-rebalance-bot`, `analytics-dashboard`) — this is how you'll identify it later
5. Click **Create API key**

Your plaintext key is shown **only once** and looks like:

```
veda_user_live_Bf9MaVT6W09KEJIOHfK9HPeBKNgB9uVU
```

Copy it into your secret manager now. You cannot retrieve it later — if you lose it, revoke and create a new one.

{% hint style="warning" %}
The key inherits the role and permissions of the user who created it. Treat it like a password: do not check it into source control, do not paste it into shared logs, and rotate it if you suspect exposure.
{% endhint %}

### Capacity & lifecycle

* Each user can have up to **10 active keys**
* Keys do not expire by default
* You can **revoke** a key at any time from the same settings page; revoked keys stop authenticating immediately
* Deactivated user accounts will stop authenticating via API key

## 2. Make your first authenticated call

Pass the key as a Bearer token in the `Authorization` header:

{% tabs %}
{% tab title="cURL" %}

```bash
curl https://api.veda.tech/v1/tx-builder/health \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const response = await fetch("https://api.veda.tech/v1/tx-builder/health", {
  headers: {
    Authorization: `Bearer ${process.env.VEDA_API_KEY}`,
  },
});

const data = await response.json();
console.log(data);
```

{% endtab %}
{% endtabs %}

A `200 OK` with a JSON body means your key works.

## 3. Confirm the response

A successful authenticated call against `/v1/tx-builder/health` returns a small JSON body:

```bash
curl https://api.veda.tech/v1/tx-builder/health \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

```json
{ "status": "healthy" }
```

If you get back the JSON above with a `200 OK`, your key is good. From here, real work happens against vault-scoped endpoints — see [Transaction Builder](/api/transaction-builder) for the full walkthrough, including how to list a vault's permitted actions and build rebalance calldata.

## Next steps

* [Transaction Builder](/api/transaction-builder) — discover actions, inspect constraints, and build rebalance calldata
* [API Reference](/api/api-reference) — the full endpoint surface in OpenAPI form
* [Change Log](/api/change-log) — what's new, what's deprecated, and what's coming


# Vaults

Endpoints for discovering the vaults that belong to your organization and inspecting state on a specific vault. The API uses a "tenant" to represent your organization. All endpoints are tenant-scoped — the tenant is resolved from your API key, and vaults outside your tenancy are not visible.

For authentication, base URL, request/response conventions, and the error envelope, see the [API Reference](/api/api-reference). Create an API key first via [Quick Start](/api/quick-start). Examples below assume the key is in `$VEDA_API_KEY`.

## Concepts

A **vault** is a set of smart contracts — built on Veda's BoringVault architecture — that abstracts DeFi complexity via a risk manager (also referred to as a curator), and adds enterprise compliance controls. A vault generates yield by allocating depositor funds, per the curator's instructions, to trusted DeFi protocols using predefined yield strategies. Depositors receive **vault receipt tokens** that prove ownership of their deposited funds, and only depositors can withdraw — not Veda, not the curator.

A vault can be deployed on one or more chains; the same `vault_address` appears on each chain it's been deployed to. Its Manager contract on each chain holds that chain's current **merkle root** — a single onchain commitment to the allowlist of actions the curator (or a delegated strategist) is permitted to execute there. For how the allowlist works and how the underlying tree is structured, see [Policy Manager & Merkle Trees](/api/policy-manager-and-merkle-trees).

{% hint style="info" %}
**Tenant denial returns 404, not 403.** Asking for a vault that isn't part of your tenant returns `404 vault_not_found` — the API does not distinguish "doesn't exist" from "exists but not yours."
{% endhint %}

***

## 1. List vaults

```
GET /v1/vaults
```

Returns the vaults that belong to the tenant on your API key, across every chain.

### Query parameters

| Name     | Type   | Required | Notes                                                                                 |
| -------- | ------ | -------- | ------------------------------------------------------------------------------------- |
| `cursor` | string | No       | Opaque cursor from a previous response's `page.next_cursor` — omit on the first call. |

### Example request

```bash
curl https://api.veda.tech/v1/vaults \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

### Example response

```json
{
  "data": [
    {
      "vault_address": "0xFDea370fa75353e650Cd6b8055600B04a47F68c2",
      "name":          "Veda Demo Vault",
      "chains":        ["ethereum", "monad"],
      "tenant":        "veda-demo",
      "deployed_at":   "2026-06-03T07:16:26.467008Z",
      "status":        "active",
      "links": {
        "ethereum": {
          "self":  "/vaults/ethereum/0xFDea370fa75353e650Cd6b8055600B04a47F68c2",
          "roots": "/vaults/ethereum/0xFDea370fa75353e650Cd6b8055600B04a47F68c2/roots"
        },
        "monad": {
          "self":  "/vaults/monad/0xFDea370fa75353e650Cd6b8055600B04a47F68c2",
          "roots": "/vaults/monad/0xFDea370fa75353e650Cd6b8055600B04a47F68c2/roots"
        }
      }
    }
  ],
  "page": {
    "next_cursor": "AXsiYWZ0ZXIiOnsiZGVwbG95ZWRfYXQiOiIyMDI2…",
    "page_size":   20,
    "has_more":    true
  }
}
```

* `chains` is the set of chains the vault is deployed on.
* `links` is keyed by chain — each chain has its own `self` and `roots` resource. The link strings are returned unversioned (no `/v1/` prefix); they're resource paths relative to the API host. Prepend `/v1` (or the base URL) when calling them.

### Errors

| Status | Code              | Cause                                |
| ------ | ----------------- | ------------------------------------ |
| `401`  | `unauthenticated` | Missing, expired, or revoked API key |
| `429`  | `rate_limited`    | API key rate limit exceeded          |

See [API Reference → Errors](/api/api-reference#errors) for the envelope and the shape of authentication / rate-limit responses.

***

## 2. Get the latest metrics snapshot

```
GET /v1/vaults/{chain}/{vault_address}/metrics/snapshot/latest
```

Returns the most recent metrics snapshot for a vault on a given chain. Snapshots are produced daily by the share-price runner and capture share price, total assets, total supply, per-protocol position breakdown, and asset prices — all at a specific block.

### Path parameters

| Name            | Type   | Notes                                                                |
| --------------- | ------ | -------------------------------------------------------------------- |
| `chain`         | string | Lowercase chain slug — see [Chain Support](/resources/chain-support) |
| `vault_address` | string | The BoringVault contract address                                     |

### Example request

```bash
curl https://api.veda.tech/v1/vaults/monad/0x1C8a336051D2024E318A229d01F9F6CF96efD316/metrics/snapshot/latest \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

### Example response

```json
{
  "data": {
    "chain":         "monad",
    "vault_address": "0x1C8a336051D2024E318A229d01F9F6CF96efD316",
    "block_number":  84732067,
    "as_of":         "2026-06-30T18:12:51Z",
    "snapshot_type": "yield_streaming",
    "share_price":   "1.001557",
    "total_assets":  "6749.023149",
    "total_supply":  "6737.890909",
    "positions": [
      { "protocol": "ERC20Position",          "asset": "USDC", "balance": "0.00861"     },
      { "protocol": "ERC20Position",          "asset": "mUSD", "balance": "337.201012"  },
      { "protocol": "SteakhouseCorePosition", "asset": "USDC", "balance": "1320.265712" },
      { "protocol": "SteakhouseCorePosition", "asset": "mUSD", "balance": "5091.547819" }
    ],
    "prices": {
      "monad": {
        "USDC": "1",
        "mUSD": "1"
      }
    },
    "base_asset": "mUSD",
    "yield_streaming": {
      "vested_amount":            "0.641343854687",
      "vesting_duration_seconds": 43200
    }
  }
}
```

* `as_of` is the ISO-8601 UTC timestamp of the snapshot's source block; `block_number` is that block.
* `snapshot_type` indicates the metric model used for this vault (e.g. `yield_streaming`). Type-specific fields (like the `yield_streaming` block below) only appear when the corresponding `snapshot_type` is active.
* `share_price`, `total_assets`, `total_supply`, position `balance`s, prices in `prices`, and `yield_streaming.vested_amount` are returned as **strings** to preserve full precision for assets whose values can fall outside safe float ranges.
* `positions` is the per-protocol breakdown of vault holdings as of `block_number`. Each entry is `{ protocol, asset, balance }`. To value a position in the vault's base asset, look up its price at `prices[chain][asset]` and multiply: `balance × price`.
* `prices` is a top-level chain → asset → string-price map. The base case is one chain (the vault's own); the structure leaves room for cross-chain holdings.
* `base_asset` is the asset that `share_price`, `total_assets`, and `total_supply` are denominated in. May come back as `"unknown"` for snapshots where the base asset hasn't been resolved yet.
* `yield_streaming` is present only when `snapshot_type` is `yield_streaming` — see [About yield streaming](#about-yield-streaming) below for what these fields represent and why the vault uses this model.

### About yield streaming

Yield-streaming vaults distribute earned yield linearly into the share price over a configurable vesting window, instead of applying it as a single rate jump. This defends against MEV and other value-extraction attacks on discrete rate updates — an attacker who front-runs a rate jump only captures the sliver of yield that has vested between their deposit and its execution, so the attack isn't profitable.

When `snapshot_type` is `yield_streaming`, the `yield_streaming` block on the response reports the current vesting tranche:

* **`vested_amount`** (string, denominated in `base_asset`) — the size of the yield tranche being streamed into the share price over the current window. This entire amount accrues into `share_price` linearly across the window.
* **`vesting_duration_seconds`** (int) — length of the vesting window in seconds. Production vaults typically use `43200` (12 hours).

### Errors

| Status | Code              | Cause                                                        |
| ------ | ----------------- | ------------------------------------------------------------ |
| `401`  | `unauthenticated` | Missing, expired, or revoked API key                         |
| `404`  | `vault_not_found` | Vault does not exist on this chain, or is not in your tenant |
| `429`  | `rate_limited`    | API key rate limit exceeded                                  |

***

## 3. List metrics snapshot history

```
GET /v1/vaults/{chain}/{vault_address}/metrics/snapshot
```

Returns the history of metrics snapshots for a vault on a given chain — newest first. Each entry has the same shape as [Get the latest metrics snapshot](#id-2.-get-the-latest-metrics-snapshot). Cursor-paginated.

### Path parameters

| Name            | Type   | Notes                                                                |
| --------------- | ------ | -------------------------------------------------------------------- |
| `chain`         | string | Lowercase chain slug — see [Chain Support](/resources/chain-support) |
| `vault_address` | string | The BoringVault contract address                                     |

### Query parameters

| Name     | Type   | Required | Notes                                                                                 |
| -------- | ------ | -------- | ------------------------------------------------------------------------------------- |
| `cursor` | string | No       | Opaque cursor from a previous response's `page.next_cursor` — omit on the first call. |

### Example request

```bash
curl https://api.veda.tech/v1/vaults/monad/0x1C8a336051D2024E318A229d01F9F6CF96efD316/metrics/snapshot \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

### Example response (abbreviated)

```json
{
  "data": [
    {
      "chain":           "monad",
      "vault_address":   "0x1C8a336051D2024E318A229d01F9F6CF96efD316",
      "block_number":    84732067,
      "as_of":           "2026-06-30T18:12:51Z",
      "snapshot_type":   "yield_streaming",
      "share_price":     "1.001557",
      "total_assets":    "6749.023149",
      "total_supply":    "6737.890909",
      "positions":       [ /* … */ ],
      "prices":          { "monad": { "USDC": "1", "mUSD": "1" } },
      "base_asset":      "mUSD",
      "yield_streaming": { "vested_amount": "0.641343854687", "vesting_duration_seconds": 43200 }
    },
    {
      "chain":           "monad",
      "vault_address":   "0x1C8a336051D2024E318A229d01F9F6CF96efD316",
      "block_number":    84620800,
      "as_of":           "2026-06-30T05:51:27Z",
      "snapshot_type":   "yield_streaming",
      "share_price":     "1.001501",
      "total_assets":    "6642.001144",
      "total_supply":    "6631.681047",
      "positions":       [ /* … */ ],
      "prices":          { "monad": { "mUSD": "1", "USDC": "1" } },
      "base_asset":      "mUSD",
      "yield_streaming": { "vested_amount": "0.365943748453", "vesting_duration_seconds": 43200 }
    }
  ],
  "page": {
    "next_cursor": null,
    "page_size":   20,
    "has_more":    false
  }
}
```

### Errors

| Status | Code              | Cause                                                        |
| ------ | ----------------- | ------------------------------------------------------------ |
| `401`  | `unauthenticated` | Missing, expired, or revoked API key                         |
| `404`  | `vault_not_found` | Vault does not exist on this chain, or is not in your tenant |
| `429`  | `rate_limited`    | API key rate limit exceeded                                  |

***

## 4. List roots set on a vault

```
GET /v1/vaults/{chain}/{vault_address}/roots
```

Returns the roots that have been set on a vault on a given chain — both current and historical. Tenant-scoped: a vault outside your tenant (or a chain the vault isn't deployed on) returns `404 vault_not_found`. Cursor-paginated. Default sort: `active DESC` — active roots first, then inactive.

### Path parameters

| Name            | Type   | Notes                                                                |
| --------------- | ------ | -------------------------------------------------------------------- |
| `chain`         | string | Lowercase chain slug — see [Chain Support](/resources/chain-support) |
| `vault_address` | string | The BoringVault contract address                                     |

### Query parameters

| Name     | Type   | Required | Notes                                                                                 |
| -------- | ------ | -------- | ------------------------------------------------------------------------------------- |
| `cursor` | string | No       | Opaque cursor from a previous response's `page.next_cursor` — omit on the first call. |

### Example request

```bash
curl https://api.veda.tech/v1/vaults/ethereum/0x6fDcB0654B4814c2eC1E7e9dbC4cEBf1a2038a84/roots \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

### Example response

```json
{
  "data": [
    {
      "root_hash":   "0xb8b546c6ea05423782d5dcdf55f0153dbdbb7b9877c72b8d06ae689db9751a68",
      "strategist":  "0x3000D05DFb41171c1cE9fED802C6fC77cb8e0C69",
      "active":      true,
      "set_at":      null,
      "set_tx_hash": null,
      "leaf_count":  null,
      "links": { "tree": "/trees/0xb8b546c6ea05423782d5dcdf55f0153dbdbb7b9877c72b8d06ae689db9751a68" }
    }
  ],
  "page": {
    "next_cursor": null,
    "page_size":   20,
    "has_more":    false
  }
}
```

* One entry is returned per `(root_hash, strategist)` pair — a vault that authorizes multiple strategists under the same root appears multiple times, once per strategist.

### Errors

| Status | Code              | Cause                                                            |
| ------ | ----------------- | ---------------------------------------------------------------- |
| `401`  | `unauthenticated` | Missing, expired, or revoked API key                             |
| `404`  | `vault_not_found` | Vault does not exist on this chain, **or** is not in your tenant |
| `429`  | `rate_limited`    | API key rate limit exceeded                                      |

***

## 5. List daily data

```
GET /v1/vaults/{chain}/{vault_address}/dailyData
```

Returns the daily share-price, APY, TVL, and base-asset accounting series for a vault over a date range. Cursor-paginated; the requested range is echoed back on `meta` so the response is self-describing.

{% hint style="info" %}
This endpoint uses the camel-case path segment `dailyData` to match the upstream contract; the rest of the API uses snake\_case in paths.
{% endhint %}

### Path parameters

| Name            | Type   | Notes                                                                |
| --------------- | ------ | -------------------------------------------------------------------- |
| `chain`         | string | Lowercase chain slug — see [Chain Support](/resources/chain-support) |
| `vault_address` | string | The BoringVault contract address                                     |

### Query parameters

| Name     | Type   | Required | Notes                                                                                                                        |
| -------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `from`   | string | No       | Start of the range, ISO-8601 UTC (e.g. `2026-05-01T00:00:00Z`). Omit to default to the earliest available day for the vault. |
| `to`     | string | No       | End of the range, ISO-8601 UTC (e.g. `2026-06-12T00:00:00Z`). Omit to default to the latest available day for the vault.     |
| `cursor` | string | No       | Opaque cursor from a previous response's `page.next_cursor` — omit on the first call.                                        |

Calling the endpoint without `from` / `to` returns the full series for the vault, paginated. The `meta` block on the response reflects the **effective** range applied by the server, so you can tell what window the data actually covers even when you omit one or both params.

### Example request

```bash
curl 'https://api.veda.tech/v1/vaults/ethereum/0x13Cc1b39cb259BA10cd174EAe42012e698ed7c51/dailyData?from=2026-05-01T00:00:00Z&to=2026-06-12T00:00:00Z' \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

### Example response

```json
{
  "data": [
    {
      "vault_address": "0x13Cc1b39cb259BA10cd174EAe42012e698ed7c51",
      "chain":         "ethereum",
      "as_of":         "2026-06-12T00:00:00Z",
      "block_number":  22489231,
      "daily_apy":     0.015506100540390087,
      "price_usd":     "1.00",
      "share_price":   1.082341,
      "total_assets":  "4250000.000000",
      "tvl_usd":       "4250000.00"
    }
  ],
  "meta": {
    "from": "2026-05-01T00:00:00Z",
    "to":   "2026-06-12T00:00:00Z"
  },
  "page": {
    "next_cursor": null,
    "page_size":   90,
    "has_more":    false
  }
}
```

* One entry per day in the requested range, in chronological order.
* `share_price` and `daily_apy` are floats; `total_assets`, `tvl_usd`, and `price_usd` are returned as strings to preserve full precision for assets whose value can fall outside safe float ranges.
* `daily_apy` is fractional — `0.015506…` means `1.55%`, not `155%`.
* `meta.from` / `meta.to` report the **effective** range the server applied — either the values you supplied, or the defaults (earliest and latest available days) when omitted.

### Errors

| Status | Code                | Cause                                                        |
| ------ | ------------------- | ------------------------------------------------------------ |
| `401`  | `unauthenticated`   | Missing, expired, or revoked API key                         |
| `404`  | `vault_not_found`   | Vault does not exist on this chain, or is not in your tenant |
| `422`  | `validation_failed` | `from` / `to` malformed, or `to` ≤ `from`                    |
| `429`  | `rate_limited`      | API key rate limit exceeded                                  |

***

## 6. Get performance

```
GET /v1/vaults/{chain}/{vault_address}/performance
```

Returns the vault's yield performance — a top-level annualized APY plus a breakdown of where that yield comes from.

{% hint style="info" %}
All APY and fee values in the response are **expressed as decimals**. Multiply by `100` to get a percentage — `0.043` = `4.3%`.
{% endhint %}

For a longer walkthrough of each field, see the [Performance APY User Guide](https://help.veda.tech/article/veda-api-user-guide#performance-api).

### Path parameters

| Name            | Type   | Notes                                                                |
| --------------- | ------ | -------------------------------------------------------------------- |
| `chain`         | string | Lowercase chain slug — see [Chain Support](/resources/chain-support) |
| `vault_address` | string | The BoringVault contract address                                     |

### Example request

```bash
curl https://api.veda.tech/v1/vaults/ethereum/0x13Cc1b39cb259BA10cd174EAe42012e698ed7c51/performance \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

### Example response

```json
{
  "data": {
    "vault_address":    "0x13cc1b39cb259ba10cd174eae42012e698ed7c51",
    "chain":            "ethereum",
    "as_of":            "2026-07-17T00:00:00Z",
    "window_days":      7,
    "apy":              0.008445101089285182,
    "fees":             0.0025,
    "performance_fees": 0.1,
    "global_apy_breakdown": {
      "fee":          0.003438344565476132,
      "maturity_apy": 0,
      "real_apy":     0.008445101089285182
    },
    "maturity_apy_breakdown": [],
    "real_apy_breakdown": [
      {
        "allocation": 0.9999999916128769,
        "apy":        0.012062023778707017,
        "apy_net":    0.010855821400836315,
        "chain":      "ethereum",
        "protocol":   "morpho"
      }
    ]
  }
}
```

### Top-level APY

The top-level `apy` field is the vault's annualized yield based on share-price changes over a **trailing 7-day window**. It's the source of truth for vault performance:

* **Share price is the foundation.** The vault's share price reflects total assets divided by total shares outstanding — as the vault earns yield, share price increases.
* **Daily-updated.** The share price on the API reflects the daily-updated share price.
* **7-day trailing average.** Rather than showing day-to-day volatility, the APY is smoothed over the past 7 days to give a more stable, representative number.
* **Net of fees.** The top-level APY is already net of fees.

### APY components

`global_apy_breakdown` decomposes the vault's return into three contributions:

* **`real_apy`** — variable-rate real yield
* **`maturity_apy`** — fixed-rate maturity products (e.g. dated lending)
* **`fee`** — total fees deducted, expressed as an APY drag

`real_apy_breakdown` lists per-protocol APY contributions with allocation weights. Each entry shows:

* **`allocation`** — a point-in-time snapshot of what share of vault assets is currently in that position. This is a **daily** snapshot.
* **`apy`** — the position's 7-day trailing APY, **gross** of position-level fees.
* **`apy_net`** — the same rate net of position-level fees. Only present when position-level fees apply.
* **`chain`**, **`protocol`** — where the position lives.

The time periods are intentionally different — allocation is today's snapshot, APY is a 7-day trailing average.

`maturity_apy_breakdown` lists fixed-rate maturity positions individually. Empty when the vault holds none.

### Fees

Three fee-related fields appear in the response:

* **`fees`** — platform fee, as an annual rate.
* **`performance_fees`** — performance fee, the rate applied to generated yield. **Nullable** — comes back as `null` for vaults with no performance fee configured.
* **`fee`** (inside `global_apy_breakdown`) — total fees deducted, expressed as an APY drag.

Fees are stored in **basis points** on-chain (1 bps = 0.01%) and converted to **decimals** in the API response.

### Other response fields

* `as_of` is the ISO-8601 UTC timestamp the summary is anchored to (start of the day it was computed for).
* `window_days` is fixed at `7 days`.
* `vault_address` may come back lowercased today rather than EIP-55 checksummed — compare case-insensitively.

### Errors

| Status | Code              | Cause                                                        |
| ------ | ----------------- | ------------------------------------------------------------ |
| `401`  | `unauthenticated` | Missing, expired, or revoked API key                         |
| `404`  | `vault_not_found` | Vault does not exist on this chain, or is not in your tenant |
| `429`  | `rate_limited`    | API key rate limit exceeded                                  |

***

**Go on to next:** [Policy Manager & Merkle Trees](/api/policy-manager-and-merkle-trees) — how a vault's allowlist is encoded as a merkle tree and committed onchain.


# Policy Manager & Merkle Trees

Veda vaults enforce an **allowlist-only** policy: a vault's strategist can only perform pre-approved actions. Nothing else is callable through the vault, regardless of who initiates the call. This page covers how that policy is represented and committed onchain (aka the Merkle Tree), and how to fetch the underlying data via the API.

## Allowlist-only policy

A Veda vault generates yield by allocating depositor funds, per the curator's instructions, to trusted DeFi protocols using predefined yield strategies. The vault's Manager contract enforces this by maintaining a strict list of actions the strategist is allowed to take, encoded as a **merkle tree** — supply USDC to Aave V3 core, swap MORPHO into USDT via 1Inch, bridge USDC from Ethereum to Base via CCTP, and so on.

Actions outside the list cannot be executed through the vault. This is the core security property — the surface area of the vault is exactly the set of pre-approved actions, and that surface is verifiable by anyone reading onchain.

## How merkle trees encode the allowlist

The allowlist is materialized off-chain as a **merkle tree**: each permitted action is one **leaf**, and leaves are hashed together pairwise up the tree to a single root hash at the top. A tree can have thousands of leaves; its root is one 32-byte value.

To execute an action, the strategist sends the call to the Manager along with a **merkle proof** — the small set of sibling hashes needed to reconstruct the path from that action's leaf up to the root. The Manager hashes the action, walks the proof, and accepts the call only if the result matches the root it has stored. If the action isn't in the tree, or its parameters fall outside what the leaf permits, the Manager reverts.

The [Transaction Builder](/api/transaction-builder) does this leaf lookup and proof construction for you — its responses contain calldata that already embeds the correct proof. Fetching the raw tree is rarely necessary in normal use; it's exposed here for callers who want to verify proofs themselves, audit the allowlist offline, or build alternative tooling.

## How roots fit in

Each vault has a **current root** stored on its Manager contract. Updating the allowlist — adding a new protocol, tightening a constraint, removing an action — means computing a new tree off-chain, taking its root, and setting that root on the Manager.

***

## Fetch a tree by root hash

```
GET /v1/trees/{root_hash}
```

Returns the merkle tree for a root hash. Globally addressable and content-cacheable.

### Path parameters

| Name        | Type   | Notes                                                       |
| ----------- | ------ | ----------------------------------------------------------- |
| `root_hash` | string | 64-character hex string. A leading `0x` prefix is optional. |

### Example request

```bash
curl https://api.veda.tech/v1/trees/0xb8b546c6ea05423782d5dcdf55f0153dbdbb7b9877c72b8d06ae689db9751a68 \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

### Example response

```json
{
  "data": {
    "root_hash":  "0xb8b546c6ea05423782d5dcdf55f0153dbdbb7b9877c72b8d06ae689db9751a68",
    "format":     "solidity",
    "leaf_count": 9,
    "depth":      4,
    "tree":       { "metadata": { "...": "..." }, "merkle_tree": [], "leaves": [] }
  }
}
```

Common metadata (`root_hash`, `format`, `leaf_count`, `depth`) is hoisted above the format-specific `tree` payload so clients don't have to branch on `format` to read it. The shape of `tree` itself depends on `format`:

* `solidity` trees have keys `metadata`, `merkle_tree`, `leaves`.
* `rust` trees have keys `leaves`, `root`, `layers`.

### Errors

| Status | Code                | Cause                                                                                                                                                                                |
| ------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `400`  | `invalid_root_hash` | `root_hash` is not 64 hex characters (with or without `0x` prefix)                                                                                                                   |
| `401`  | `unauthenticated`   | Missing, expired, or revoked API key                                                                                                                                                 |
| `404`  | `tree_not_found`    | No tree for this root, no vault in your tenant uses this root, or the root is pending — fetch it via [Fetch a pending tree by root hash](#fetch-a-pending-tree-by-root-hash) instead |
| `429`  | `rate_limited`      | API key rate limit exceeded                                                                                                                                                          |

***

## Fetch a pending tree by root hash

```
GET /v1/trees/{root_hash}/pending
```

Returns a **pending** merkle tree — one that has been generated off-chain but has not yet been set on the vault's Manager contract. Use this to review a tree before the onchain root rotation and confirm it matches what you expect.

### Path parameters

| Name        | Type   | Notes                                                       |
| ----------- | ------ | ----------------------------------------------------------- |
| `root_hash` | string | 64-character hex string. A leading `0x` prefix is optional. |

### Example request

```bash
curl https://api.veda.tech/v1/trees/0xabc1230000000000000000000000000000000000000000000000000000000000/pending \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

### Example response

Same shape as [Fetch a tree by root hash](#fetch-a-tree-by-root-hash) — `data.root_hash`, `data.format`, `data.leaf_count`, `data.depth`, and the format-specific `data.tree` payload.

### Pending vs onchain

A root is either pending or onchain, never both — the two endpoints partition the tree namespace by state, so they return mirror-image `200` / `404` responses:

| Request                             | Root's current state            | Response             |
| ----------------------------------- | ------------------------------- | -------------------- |
| `GET /v1/trees/{root_hash}`         | Onchain (current or historical) | `200` with the tree  |
| `GET /v1/trees/{root_hash}`         | Pending, not yet onchain        | `404 tree_not_found` |
| `GET /v1/trees/{root_hash}/pending` | Pending, not yet onchain        | `200` with the tree  |
| `GET /v1/trees/{root_hash}/pending` | Onchain (current or historical) | `404 tree_not_found` |

Once a pending root is set onchain (typically via a rebalance-window rotation), `/pending` starts returning `404` for that root and the base [`/v1/trees/{root_hash}`](#fetch-a-tree-by-root-hash) starts returning `200`.

### Errors

| Status | Code                | Cause                                                                                                                                                                                |
| ------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `400`  | `invalid_root_hash` | `root_hash` is not 64 hex characters (with or without `0x` prefix)                                                                                                                   |
| `401`  | `unauthenticated`   | Missing, expired, or revoked API key                                                                                                                                                 |
| `404`  | `tree_not_found`    | No pending tree for this root, no vault in your tenant uses this root, or the root is already onchain — fetch it via [Fetch a tree by root hash](#fetch-a-tree-by-root-hash) instead |
| `429`  | `rate_limited`      | API key rate limit exceeded                                                                                                                                                          |


# Transaction Builder

The Transaction Builder API turns a high-level intent — "supply 1,000 USDC to Aave V3" or "bridge USDC from Ethereum to Base via CCTP" — into ready-to-submit calldata for a vault's Manager contract. It's the same engine that powers the rebalance feature in the Veda Console, exposed for programmatic use.

{% hint style="danger" %}
**Always verify calldata independently before signing.** The Transaction Builder is a convenience — it is not a substitute for review. Decode the returned `encoded_tx_data` against the Manager ABI and run it through [Tenderly](https://dashboard.tenderly.co/) or another simulator before broadcasting. Confirm the target address and every encoded argument match what you intended. **Never rely solely on the API response for correctness.** Independent simulation is the last line of defense.
{% endhint %}

## Concepts

Veda vaults route depositor funds to trusted DeFi protocols according to the curator's predefined yield strategies. A **rebalance** — moving funds between positions, swapping, supplying, withdrawing — is one or more of those onchain actions, executed through the vault's Manager contract.

The Manager only accepts actions that are present as leaves in the vault's active merkle tree; every call must carry a merkle proof against the root pinned on the Manager (see [Policy Manager & Merkle Trees](/api/policy-manager-and-merkle-trees)). The Transaction Builder embeds the right proof for the action you ask it to build, so the calldata it returns is one the Manager will accept.

The API is **build-only**: it returns encoded calldata and a target address; you sign and submit the transaction from your strategist address.

The workflow:

1. **Discover** what actions are available for a vault — `GET /actions`
2. **Inspect constraints** for actions with correlated parameters — `GET /constraints`
3. **Build** a single action — `POST /execute` — or several atomically — `POST /execute-multiple`
4. **Submit** the returned `encoded_tx_data` to the Manager from the strategist address

Every action endpoint is scoped by three path parameters:

| Param                | Meaning                                                                                                                                               |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `chain`              | Lowercase chain slug (e.g. `ethereum`, `base`, `arbitrum`). See [Chain Support](/resources/chain-support) for the full list.                          |
| `vault_address`      | The BoringVault contract address                                                                                                                      |
| `strategist_address` | The strategist address whose merkle tree / permissions are being used. A single vault can have multiple strategists with different permitted actions. |

***

## 1. List available actions

```
GET /v1/tx-builder/api/actions/{chain}/{vault_address}/{strategist_address}
```

Returns every action the vault's merkle tree authorizes for the given strategist, along with the parameter metadata you need to build a transaction. No request body, no query parameters.

### Example request

```bash
curl https://api.veda.tech/v1/tx-builder/api/actions/ethereum/0xA20f97813014129E7609171d2D3AA3da5206259e/0x2322ba43eFF1542b6A7bAeD35e66099Ea0d12Bd1 \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

### Response structure

A JSON object keyed by **route** (e.g. `aavev3/supply`). Each entry describes one action:

| Field              | Type    | Meaning                                                                               |
| ------------------ | ------- | ------------------------------------------------------------------------------------- |
| `name`             | string  | Human-readable action name                                                            |
| `protocol`         | string  | Protocol identifier (e.g. `AaveV3`, `1Inch`)                                          |
| `protocol_app_url` | string  | Link to the protocol's app, when applicable                                           |
| `description`      | string  | What the action does                                                                  |
| `has_constraints`  | boolean | If `true`, params are correlated — call `/constraints/{route}` for valid combinations |
| `params`           | array   | Parameter definitions (see below)                                                     |

Each `params[i]` is:

| Field             | Type            | Meaning                                                                                                                      |
| ----------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `name`            | string          | Parameter name to pass in the execute request                                                                                |
| `type`            | string          | Python type name (`str`, `int`, `float`, `Decimal`)                                                                          |
| `description`     | string          | Human-readable description                                                                                                   |
| `required`        | boolean         | Whether the parameter must be provided                                                                                       |
| `default_value`   | any \| null     | Default if not provided (only meaningful for non-required params)                                                            |
| `choices`         | array \| `null` | Allowed values. `[]` means freeform; `null` means optional and may be omitted; a populated list means you must pick from it. |
| `min_value`       | number \| null  | Minimum valid value, if applicable                                                                                           |
| `max_value`       | number \| null  | Maximum valid value, if applicable                                                                                           |
| `omitToUseAll`    | boolean         | If `true`, omitting this parameter uses the vault's full balance of the token                                                |
| `acceptRawString` | boolean         | If `true`, the value is forwarded as-is (no numeric conversion)                                                              |

{% hint style="info" %}
**Grouped choices.** Most params have `choices` as a flat array of strings (`["USDC", "USDT"]`). Some params use **nested arrays** (`[["USDC", "0xa0b8..."], ["USDT", "0xdac1..."]]`) where each inner array is `[display_label, value]`. When building a UI, check whether the first element of `choices` is itself an array to decide which format you're dealing with.
{% endhint %}

### Example response (abbreviated)

```json
{
  "aavev3/supply": {
    "name": "Supply",
    "protocol": "AaveV3",
    "protocol_app_url": "https://app.aave.com",
    "description": "Supply tokens to AaveV3",
    "has_constraints": false,
    "params": [
      { "name": "token",  "type": "str",   "required": true, "choices": ["USDC", "USDT"] },
      { "name": "amount", "type": "float", "required": true, "choices": [] },
      { "name": "market", "type": "str",   "required": true, "choices": ["core"] }
    ]
  },
  "one_inch/swap": {
    "name": "Swap",
    "protocol": "1Inch",
    "protocol_app_url": "https://app.1inch.io",
    "description": "Swap tokens using 1Inch",
    "has_constraints": true,
    "params": [
      { "name": "token_in",  "type": "str",   "required": true, "choices": ["MORPHO", "USDC", "USDT"] },
      { "name": "token_out", "type": "str",   "required": true, "choices": ["USDC", "USDT"] },
      { "name": "amount",    "type": "float", "required": true, "choices": [] },
      {
        "name": "slippage_tolerance",
        "type": "float",
        "required": true,
        "default_value": 0.0001,
        "choices": [],
        "min_value": 0,
        "max_value": 0.1
      }
    ]
  }
}
```

{% hint style="info" %}
When `has_constraints` is `true`, the values in each param's `choices` are the **projection** of the valid combinations onto that one param. You still need to call the constraints endpoint to know which combinations are actually valid (e.g. `USDC → USDT` may be allowed but `USDC → USDC` is not).
{% endhint %}

***

## 2. Inspect parameter constraints

When `has_constraints` is `true`, not every combination of `choices` is valid. The constraints endpoint returns the valid combinations.

```
GET /v1/tx-builder/api/actions/{chain}/{vault_address}/{strategist_address}/constraints/{route}
```

### Example request

```bash
curl https://api.veda.tech/v1/tx-builder/api/actions/ethereum/0xA20f97813014129E7609171d2D3AA3da5206259e/0x2322ba43eFF1542b6A7bAeD35e66099Ea0d12Bd1/constraints/one_inch/swap \
  -H "Authorization: Bearer $VEDA_API_KEY"
```

### Example response

```json
{
  "route": "one_inch/swap",
  "constraints": [
    { "token_in": "MORPHO", "token_out": "USDC" },
    { "token_in": "MORPHO", "token_out": "USDT" },
    { "token_in": "USDC",   "token_out": "USDT" },
    { "token_in": "USDT",   "token_out": "USDC" }
  ]
}
```

Each entry in `constraints` is one valid combination. Use this to drive dependent dropdowns in a UI, or to filter to a single combination in a script. Routes where `has_constraints` is `false` have fully independent parameters — any combination of values from `choices` is valid.

A `404` from this endpoint means the route has no parameter constraints (i.e. you didn't need to call it).

***

## 3. Build a single action

```
POST /v1/tx-builder/api/execute/{chain}/{vault_address}/{tail:path}
```

The `tail` matcher captures everything after the vault. It accepts either of:

* `{strategist_address}/{route}` — recommended; explicit
* `{route}` — the API resolves the strategist for the vault

When `tail` begins with a `0x…`-prefixed 42-character string, that prefix is treated as the strategist address and the rest is the route. The route itself contains a slash (e.g. `aavev3/supply`), which is why `tail:path` is used.

### Request body

| Field      | Type                  | Default | Description                                                                                                                                                                       |
| ---------- | --------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `params`   | object (string → any) | `{}`    | Key-value map of action parameters, matching the `/actions` metadata for this route                                                                                               |
| `verbose`  | boolean               | `false` | Return detailed simulation output — token transfers, gas cost in ETH, and protocol-level metadata in `action_api_response` (including warnings). Recommended for any review step. |
| `skip_sim` | boolean               | `false` | Skip the Tenderly simulation. Set `true` for faster responses or when you've already simulated.                                                                                   |

### Example request

```bash
curl -X POST \
  -H "Authorization: Bearer $VEDA_API_KEY" \
  -H "Content-Type: application/json" \
  https://api.veda.tech/v1/tx-builder/api/execute/ethereum/0xA20f97813014129E7609171d2D3AA3da5206259e/0x2322ba43eFF1542b6A7bAeD35e66099Ea0d12Bd1/aavev3/supply \
  -d '{
    "params": { "token": "USDC", "amount": 1000, "market": "core" },
    "skip_sim": false
  }'
```

### Response structure

| Field                     | Type              | Always present? | Meaning                                                                                          |
| ------------------------- | ----------------- | --------------- | ------------------------------------------------------------------------------------------------ |
| `encoded_tx_data`         | string            | Yes             | Calldata (hex, `0x`-prefixed) to submit to the vault's Manager contract                          |
| `target`                  | string            | Yes             | Manager contract address — the `to` of your transaction                                          |
| `description`             | string            | Yes             | Human-readable description of the action being built                                             |
| `action_api_response`     | object \| null    | Yes             | Protocol-specific metadata. See [Simulation warnings](#simulation-warnings) for the warning keys |
| `simulation_status`       | boolean \| string | When simulated  | `true` if the Tenderly simulation succeeded; may also be an error string on failure              |
| `tenderly_simulation_url` | string \| null    | When simulated  | Link to the Tenderly simulation                                                                  |
| `simulation_logs`         | array             | When simulated  | Logs emitted during the simulation (when available)                                              |
| `simulation_gas_used`     | number \| null    | When simulated  | Gas used during the simulation (when available)                                                  |
| `simulation_gas_cost_eth` | string \| null    | When verbose    | Estimated gas cost denominated in ETH                                                            |
| `token_transfers`         | array             | When verbose    | Structured list of tokens moved during the simulation (see below)                                |
| `simulation_skipped`      | boolean           | When skipped    | Present and `true` when `skip_sim: true` was passed                                              |

#### Token transfers

When `verbose: true`, the response includes a `token_transfers` array with one entry per token movement observed during the simulation:

| Field           | Type                     | Meaning                                               |
| --------------- | ------------------------ | ----------------------------------------------------- |
| `token`         | string                   | Token symbol (e.g. `USDC`)                            |
| `token_address` | string                   | Token contract address                                |
| `amount`        | string                   | Human-readable amount in display units                |
| `raw_amount`    | string                   | Amount in the token's smallest unit (wei / base unit) |
| `direction`     | `"in"` \| `"out"`        | Whether the vault receives or sends the token         |
| `dollar_value`  | string \| number \| null | Estimated USD value, when a price is available        |

### Example response

```json
{
  "encoded_tx_data": "0x244b0f6a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001...",
  "target": "0x20dCC05A7fE66d6442bE7d50C9EC41c4Bfda7f68",
  "description": "Supply tokens to AaveV3",
  "action_api_response": {
    "Input Amount": "1,000.00 USDC",
    "Output Amount": "999.87 aUSDC"
  },
  "simulation_status": true,
  "tenderly_simulation_url": "https://www.tdly.co/shared/simulation/abc123",
  "simulation_gas_used": 312418,
  "simulation_gas_cost_eth": "0.004218",
  "token_transfers": [
    {
      "token": "USDC",
      "token_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "amount": "1,000.00",
      "raw_amount": "1000000000",
      "direction": "out",
      "dollar_value": "1000.00"
    },
    {
      "token": "aUSDC",
      "token_address": "0xBcca60bB61934080951369a648Fb03DF4F96263C",
      "amount": "999.87",
      "raw_amount": "999870000",
      "direction": "in",
      "dollar_value": "999.87"
    }
  ]
}
```

{% hint style="info" %}
The `token_transfers` and `simulation_gas_cost_eth` fields are only present when the request includes `verbose: true`. Without it, you still get `simulation_status`, `simulation_gas_used`, and `tenderly_simulation_url`.
{% endhint %}

***

## 4. Build multiple actions (atomic batch)

```
POST /v1/tx-builder/api/execute-multiple/{chain}/{vault_address}/{strategist_address}
```

Build a single atomic transaction that runs several actions in order. The response is one piece of calldata that calls the Manager with all actions packed together — recommended for any rebalance that involves more than one step (e.g. swap then supply, withdraw from one position and deposit into another).

### Request body

| Field      | Type             | Default | Description                                                                                    |
| ---------- | ---------------- | ------- | ---------------------------------------------------------------------------------------------- |
| `actions`  | array of objects | —       | One entry per action. Each is `{ "route": string, "params": object }`.                         |
| `verbose`  | boolean          | `false` | Return detailed simulation output — token transfers, gas cost in ETH, and per-action metadata. |
| `skip_sim` | boolean          | `false` | Skip the Tenderly simulation                                                                   |

An empty `actions` array is rejected with `400 No actions provided`.

### Example request

Swap 1,000 USDC into USDT via 1Inch, then supply 500 USDC into Aave V3 — in a single onchain transaction:

```bash
curl -X POST \
  -H "Authorization: Bearer $VEDA_API_KEY" \
  -H "Content-Type: application/json" \
  https://api.veda.tech/v1/tx-builder/api/execute-multiple/ethereum/0xA20f97813014129E7609171d2D3AA3da5206259e/0x2322ba43eFF1542b6A7bAeD35e66099Ea0d12Bd1 \
  -d '{
    "actions": [
      {
        "route": "one_inch/swap",
        "params": {
          "token_in": "USDC",
          "token_out": "USDT",
          "amount": 1000,
          "slippage_tolerance": 0.0001
        }
      },
      {
        "route": "aavev3/supply",
        "params": { "token": "USDC", "amount": 500, "market": "core" }
      }
    ],
    "skip_sim": false
  }'
```

### Response structure

Same shape as `/execute`, with two differences:

* `description` is always `"Multiple actions execution"`
* `action_api_response` is an **array** — one entry per action, in the same order as `actions`

### Example response

```json
{
  "encoded_tx_data": "0x244b0f6a...",
  "target": "0x20dCC05A7fE66d6442bE7d50C9EC41c4Bfda7f68",
  "description": "Multiple actions execution",
  "action_api_response": [
    { "expected_out": "999.42 USDT", "tx_payload": { "...": "..." } },
    null
  ],
  "simulation_status": true,
  "tenderly_simulation_url": "https://www.tdly.co/shared/simulation/def456"
}
```

***

## Error handling

The Transaction Builder endpoints predate the standardized error envelope used by the rest of the v1 API. Non-2xx responses come back on a `detail` field, which can be a string (`{ "detail": "Vault not found" }`), an object (`{ "detail": { "error": "...", "details": "..." } }`), or — for `422` validation errors — a Pydantic-style array (`{ "detail": [{ "loc": [...], "msg": "...", "type": "..." }] }`). For authentication failures from the gateway, see [API Reference → Authentication errors](/api/api-reference#authentication-errors). And remember that a `200` can still carry `error` / `details` alongside `encoded_tx_data` when calldata was built but simulation failed — always check `simulation_status`.


# API Reference

The full Veda Console API surface is described by an OpenAPI 3 specification. The interactive Swagger UI is the source of truth for request and response schemas, parameter shapes, and the list of supported endpoints.

## OpenAPI / Swagger

{% hint style="info" %}
[**Open the interactive Swagger docs →**](https://api.veda.tech/docs)
{% endhint %}

* **Swagger UI:** [api.veda.tech/docs](https://api.veda.tech/docs)
* **OpenAPI JSON:** [api.veda.tech/openapi.json](https://api.veda.tech/openapi.json)
* **Version:** `1.0.0`

You can use the OpenAPI spec directly to generate clients in your language of choice (`openapi-generator`, `oapi-codegen`, `openapi-typescript`, etc.), drive contract tests, or import into Postman / Insomnia.

## Base URL

```
https://api.veda.tech
```

## Authentication

All endpoints are authenticated with an API key passed as a Bearer token:

```
Authorization: Bearer veda_user_live_...
```

API keys are created in the [Veda Console](https://console.veda.tech) — see [Quick Start](/api/quick-start).

## Rate limits & timeouts

* **Rate limit:** 60 requests per minute, per API key. When you exceed the limit, the API returns `429 Too Many Requests` — back off with exponential delay and retry.
* **Request timeout:** 30 seconds for most endpoints. Build endpoints (`/execute`, `/execute-multiple`) with simulation enabled can take significantly longer. Pass `skip_sim: true` when you don't need a Tenderly simulation — it's the most common way to get faster responses.

If you need a higher limit for a production workload, reach out to your Veda contact with the expected request volume.

## Conventions

* **JSON only.** All requests and responses are `application/json` unless noted otherwise.
* **Envelopes.** Newer endpoints ([Vaults](/api/vaults), [Policy Manager & Merkle Trees](/api/policy-manager-and-merkle-trees)) wrap responses: `{ "data": { ... } }` for a single resource, `{ "data": [ ... ], "page": { ... } }` for a collection. [Transaction Builder](/api/transaction-builder) endpoints predate this and return their payload at the top level.
* **JSON keys** are `snake_case`. Timestamps are ISO-8601 in UTC. Paths have no trailing slashes.
* **Chain slugs** are lowercase (`ethereum`, `base`, `arbitrum`, etc.). See [Chain Support](/resources/chain-support) for the full list.
* **Addresses** are EIP-55 checksummed in responses; lowercase or checksummed is accepted on request.
* **Amounts** in request bodies are in the token's display units (e.g. `1000` means 1,000 USDC, not 1,000 wei).
* **Errors** use one of two envelopes — see [Errors](#errors) below.

## Errors

Non-2xx responses from application endpoints ([Vaults](/api/vaults), [Policy Manager & Merkle Trees](/api/policy-manager-and-merkle-trees)) use a single envelope:

```json
{
  "error": {
    "code":    "snake_case_code",
    "message": "Human-readable description.",
    "details": {}
  }
}
```

`details` is an object whose contents depend on the code — `rate_limited` includes a `retry_after` value in seconds, and so on. Today `details` is most often an empty object.

**Standard codes:**

| HTTP  | Code                                        |
| ----- | ------------------------------------------- |
| `400` | `invalid_root_hash`                         |
| `404` | `vault_not_found`, `tree_not_found`         |
| `429` | `rate_limited` (with `details.retry_after`) |
| `500` | `internal_error`                            |

{% hint style="info" %}
**Tenant denial returns 404, never 403.** For tenant-scoped resources (vaults, trees), the API does not distinguish "doesn't exist" from "exists but not in your tenant" — callers cannot probe for the existence of other tenants' resources.
{% endhint %}

### Authentication errors

Authentication is enforced at the gateway, ahead of the application, so 401 / 403 responses **do not use the standardized envelope** above. They return a flat `message` field instead:

```json
{ "message": "Unauthorized" }
```

* `401 { "message": "Unauthorized" }` — no `Authorization` header.
* `403 { "message": "Forbidden" }` — header is present but the bearer is invalid, expired, or revoked.

Treat both as "re-authenticate." Once the request reaches the application, all other failures use the envelope above.

## Versioning

The Veda API uses **major versions in the URL path**. Every endpoint sits under a `/v{N}/` prefix. The current major version is `v1`.

### Deprecations

Endpoints or fields slated for removal in a future major version are marked as deprecated in the OpenAPI spec and announced in the [Change Log](/api/change-log) with at least **30 days' notice**. During the deprecation window, calls succeed and the response includes a `Deprecation` header pointing to the replacement.

### Pinning a version

Always pin the version explicitly in your client (`/v1/...`). Don't rely on host-level redirects from an unversioned path — they're not guaranteed and may change.


# Change Log

What's new, what's coming, and what's going away in the Veda API. New endpoints, breaking changes, and deprecations are announced here.

## Releases

### 2026-06 — Vaults & Trees

Three tenant-scoped endpoints for discovering vaults and inspecting the merkle roots and trees behind them.

**Available endpoints:**

* `GET /v1/vaults` — list the vaults that belong to your tenant — see [Vaults](/api/vaults)
* `GET /v1/vaults/{chain}/{vault_address}/roots` — list roots set on a vault (current and historical) — see [Vaults](/api/vaults)
* `GET /v1/trees/{root_hash}` — fetch a merkle tree by root hash (content-addressed, immutable cache) — see [Policy Manager & Merkle Trees](/api/policy-manager-and-merkle-trees)

These endpoints use a new standardized error envelope (`{ "error": { "code", "message", "details" } }`) and return `404` rather than `403` when a resource is outside your tenant, to avoid leaking existence. The Transaction Builder endpoints continue to use the legacy `{ "detail": ... }` shape until migrated separately.

### 2026-05 — Transaction Builder (public release)

The Transaction Builder API is now generally available to partner strategists.

**Available endpoints:**

* `GET /v1/tx-builder/api/actions/{chain}/{vault}/{strategist}` — list available actions
* `GET /v1/tx-builder/api/actions/{chain}/{vault}/{strategist}/constraints/{route}` — valid parameter combinations
* `POST /v1/tx-builder/api/execute/{chain}/{vault}/{strategist}/{route}` — build a single action
* `POST /v1/tx-builder/api/execute-multiple/{chain}/{vault}/{strategist}` — build an atomic batch

**Authentication:** Bearer tokens via API keys created in the [Veda Console](https://console.veda.tech).

See [Transaction Builder](/api/transaction-builder) for the full walkthrough.

## Deprecations

Deprecations will be announced here with a minimum **30-day** notice before removal. Deprecated fields and endpoints continue to work during that window, with a warning surfaced in the response.

* *No deprecations at this time.*

## Conventions

* **Dates** in this changelog are `YYYY-MM` for monthly groupings; specific releases use `YYYY-MM-DD`.
* **Breaking changes** are called out explicitly with the word "Breaking" and a migration note.
* **Additive changes** (new endpoints, new optional fields, new chains) are not considered breaking.


# Security & Risk Controls

## Risks

Interacting with DeFi inherently involves risk, which broadly falls into two categories:

**Smart Contract Risk:** The possibility of financial loss from coding errors or unintended consequences within the contracts that power DeFi protocols.

**Economic Risk:** The economic uncertainty related to liquidity, protocol mechanics, market movements, strategy effectiveness, and asset volatility.

Veda vaults work to mitigate these risks using best practices in smart contract development and DeFi curation.


# Smart Contract Security

Smart contract security governs the core vault architecture and operational safeguards, defining how the vault functions and constraining its capabilities to pre-approved actions. Veda's framework includes:

### Minimal Surface Area

Veda vaults expose only two public functions:

* **Deposit** to supply assets
* **Withdraw** to redeem assets

This reduced surface area minimizes potential attack vectors and defines a clear user interaction model, making reliable safeguards easier to build.

### Merkle Verification System

* Every action a vault can perform - whether deploying liquidity, staking or rebalancing - is pre-registered, hashed, and embedded in a Merkle tree
* Before executing any action, the vault must prove its inclusion in this Merkle root, ensuring that only pre-approved actions are executable
* This system makes it impossible for arbitrary transactions or strategy changes to occur

### Transaction Safeguards

* **Share Lock Period:** Newly issued vault shares are locked for a brief period to neutralize flash loan manipulation risks
* **Delayed Withdrawals:** Withdrawals are subject to a time delay, creating a monitoring window for identifying and responding to irregularities

### Onchain Monitoring

* Veda tracks both internal positions and external market dynamics.
* Veda also uses third-party monitoring systems to detect malicious behaviour targeting Veda contracts and the underlying protocols its vaults are exposed to.
* Veda vaults are also part of multiple ongoing bug bounty programs operated by our integration partners.

### Audits

Veda contracts are used by many of the top protocols in DeFi, including ether.fi, Plasma, Lombard, TAC, Rings, and TurtleClub, making the BoringVault one of the most audited DeFi contracts in production.

Audit firms commissioned to evaluate the BoringVault include Spearbit, Macro, Secure3 & Hexens.


# Audits

| Scope              | Purpose                                                                                                                                                     | Report                                                                                                             | Auditor            |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------ |
| Full Architecture  | Comprehensive initial audit of the core Boring Vault architecture including BoringVault, Teller, Accountant, Queue, Solver, and decoder/sanitizer contracts | [A-4](https://macroaudits.com/library/audits/sevenSeas-4)                                                          | 0xMacro            |
| Full Architecture  | Full security review of the Boring Vault Arctic version covering the complete protocol architecture                                                         | [Spearbit (Cantina)](https://github.com/Veda-Labs/boring-vault/blob/main/audit/spearbit-boring-vault-arctic-0.pdf) | Spearbit (Cantina) |
| Accountant, Teller | AccountantWithRateProviders updates for performance fees, high water mark, DelayedWithdraw, and TellerWithRemediation                                       | [A-8](https://macroaudits.com/library/audits/sevenSeas-8)                                                          | 0xMacro            |
| Accountant         | ReserveDecoderAndSanitizer and private Position Manager for Into the Block integration                                                                      | [A-9](https://macroaudits.com/library/audits/sevenSeas-9)                                                          | 0xMacro            |
| Teller             | Bridging, EtherFi, PancakeSwapV3, CCIP, ITBPosition, and Karak decoders for authorizing trusted protocols on bulk deposits                                  | [A-10](https://macroaudits.com/library/audits/sevenSeas-10)                                                        | 0xMacro            |
| Teller             | EtherFiLiquidEthDecoderAndSanitizer updates for improved EtherFi integration                                                                                | [A-15](https://macroaudits.com/library/audits/sevenSeas-15)                                                        | 0xMacro            |
| Queue, Solver      | UsualMoneyDecoderAndSanitizer and EtherFiLiquidUsdDecoderAndSanitizer for Usual Money protocol integration                                                  | [A-18](https://macroaudits.com/library/audits/sevenSeas-18)                                                        | 0xMacro            |
| Accountant, Teller | HyperlaneDecoderAndSanitizer and LayerZero Teller for cross-chain bridging capabilities                                                                     | [A-19](https://macroaudits.com/library/audits/sevenSeas-19)                                                        | 0xMacro            |
| Solver             | BoringSolver upgrade allowing the solver to cover withdrawal deficits                                                                                       | [A-25](https://macroaudits.com/library/audits/sevenSeas-25)                                                        | 0xMacro            |
| Queue              | SymbioticVaultDecoderAndSanitizer and BoringOnChainQueue capacity limit feature                                                                             | [A-27](https://macroaudits.com/library/audits/sevenSeas-27)                                                        | 0xMacro            |
| Teller             | TellerWithMultiAssetSupport improvements for multi-asset deposit handling                                                                                   | [A-36](https://macroaudits.com/library/audits/sevenSeas-36)                                                        | 0xMacro            |
| Solver             | BGTRewardVaultDecoderAndSanitizer, OogaBoogaDecoderAndSanitizer, and DeriveDecoder for USDT redemption support                                              | [A-38](https://macroaudits.com/library/audits/sevenSeas-38)                                                        | 0xMacro            |
| Solver             | BoringSolver upgrade for handling excess, rFLRDecoderAndSanitizer, and AgglayerDecoder for cross-chain bridging                                             | [A-44](https://macroaudits.com/library/audits/sevenSeas-44)                                                        | 0xMacro            |
| Teller             | Teller upgrade introducing deposit caps to limit inflows                                                                                                    | [A-45](https://macroaudits.com/library/audits/sevenSeas-45)                                                        | 0xMacro            |


# Chain Support

Chain slugs accepted by the Veda API, and the corresponding chain IDs.

The chains below are networks Veda is integrated with. The **slug** column is the value to pass as the `chain` path parameter on every API endpoint — slugs are always lowercase.

## Mainnets

| Slug        | Chain           | Chain ID |
| ----------- | --------------- | -------- |
| `ethereum`  | Ethereum        | 1        |
| `arbitrum`  | Arbitrum One    | 42161    |
| `base`      | Base            | 8453     |
| `optimism`  | OP Mainnet      | 10       |
| `linea`     | Linea           | 59144    |
| `bnb`       | BNB Smart Chain | 56       |
| `scroll`    | Scroll          | 534352   |
| `unichain`  | Unichain        | 130      |
| `ink`       | Ink             | 57073    |
| `berachain` | Berachain       | 80094    |
| `sonic`     | Sonic           | 146      |
| `flare`     | Flare           | 14       |
| `katana`    | Katana          | 747474   |
| `hyperevm`  | HyperEVM        | 999      |
| `plasma`    | Plasma          | 9745     |
| `sei`       | Sei             | 1329     |
| `monad`     | Monad           | 143      |

## Notes

* Chain IDs follow [chainlist.org](https://chainlist.org) where possible.
* New chains are added regularly. If a chain you need isn't listed, reach out to your Veda contact.


