Vauban Docs
Guides

Vault Router

Vault Router — Multi-Vault Deposits

The VaultRouter contract enables optimal vault selection and multi-vault deposits in a single transaction. Instead of manually comparing APYs and approving tokens for each vault, VaultRouter handles routing, approval, and deposit atomically.

How It Works

User calls VaultRouter.deposit_to_best_vault(amount, token)
  → Router queries all registered vaults
  → Selects vault with best APY + available capacity
  → Handles token approval internally
  → Deposits into selected vault
  → Returns LST shares to user
  → Resets approval to zero (safety)

Architecture

VaultRouter sits between users and VaubanVault instances:

┌──────────┐     ┌──────────────┐     ┌────────────────┐
│   User   │────►│  VaultRouter │────►│  VaubanVault   │
│          │     │              │     │  (vaSTRK)      │
│          │     │  - routing   │     ├────────────────┤
│          │     │  - approval  │     │  VaubanVault   │
│          │     │  - deposit   │     │  (vawBTC)      │
└──────────┘     └──────────────┘     └────────────────┘

Contract Interface

#[starknet::interface]
trait IVaultRouter<TContractState> {
    // Deposit to the best vault for a given token
    fn deposit_to_best_vault(
        ref self: TContractState,
        amount: u256,
        token: ContractAddress,
        receiver: ContractAddress
    ) -> (ContractAddress, u256); // (vault, shares)

    // Deposit to a specific vault
    fn deposit_to_vault(
        ref self: TContractState,
        vault: ContractAddress,
        amount: u256,
        receiver: ContractAddress
    ) -> u256; // shares

    // Admin: register/remove vaults
    fn register_vault(ref self: TContractState, vault: ContractAddress);
    fn remove_vault(ref self: TContractState, vault: ContractAddress);

    // View: get registered vaults
    fn get_vaults(self: @TContractState) -> Array<ContractAddress>;
}

Security

  • CEI pattern: All state updates before external calls
  • Approval reset: Token approvals set to zero after each deposit (prevents leftover allowance attacks)
  • Owner-only registration: Only contract owner can register/remove vaults
  • Zero-address validation: All address inputs validated
  • Reentrancy safe: No state dependencies across external calls

Integration

Frontend (Starknet.js)

import { Contract } from 'starknet';

const router = new Contract(VAULT_ROUTER_ABI, VAULT_ROUTER_ADDRESS, account);

// Approve router to spend tokens
await account.execute([
  { contractAddress: STRK_TOKEN, entrypoint: 'approve', calldata: [VAULT_ROUTER_ADDRESS, amount, 0] },
  { contractAddress: VAULT_ROUTER_ADDRESS, entrypoint: 'deposit_to_best_vault', calldata: [amount, 0, STRK_TOKEN, userAddress] }
]);

Backend API

GET /api/vaults/recommendation?token=STRK&amount=1000
→ { vault: "vaSTRK", apy: "12.5%", capacity: "80%", shares_estimate: 995 }