Skip to main content

Vault Hooks

useVaults

Fetch all active vaults with metadata, APY, and TVL. Source: ~/workspace/source/src/hooks/use-vault-data.ts:13
function useVaults(): {
  vaults: LiveVault[];
  loading: boolean;
  error: string | null;
  refresh: () => Promise<void>;
}
Example:
import { useVaults } from '@/hooks/use-vault-data';

function VaultList() {
  const { vaults, loading, error, refresh } = useVaults();
  
  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  
  return (
    <div>
      {vaults.map(vault => (
        <div key={vault.id}>
          <h3>{vault.name}</h3>
          <p>APY: {vault.apy.total.toFixed(2)}%</p>
          <p>TVL: ${(vault.tvlUsd / 1e6).toFixed(2)}M</p>
        </div>
      ))}
      <button onClick={refresh}>Refresh</button>
    </div>
  );
}
Features:
  • Auto-refreshes every 60 seconds
  • Fetches from /api/vaults
  • Returns LiveVault[] with APY breakdown, TVL, risk level, and strategy info

useVaultDetail

Get a single vault by ID.
function useVaultDetail(vaultId: string): {
  vault: LiveVault | null;
  loading: boolean;
  error: string | null;
}

useVaultRead

Read on-chain vault state (total assets, supply, share balance). Source: ~/workspace/source/src/hooks/use-vault-contract.ts:34
function useVaultRead(vaultAddress: string): {
  getTotalAssets: () => Promise<bigint>;
  getTotalSupply: () => Promise<bigint>;
  getShareBalance: (account: string) => Promise<bigint>;
  previewDeposit: (assets: bigint) => Promise<bigint>;
  previewWithdraw: (assets: bigint) => Promise<bigint>;
}
Example:
const { getTotalAssets, previewDeposit } = useVaultRead(SABLE_CONTRACTS.SENTINEL);

const assets = await getTotalAssets(); // Total WBTC in vault
const shares = await previewDeposit(BigInt(100000000)); // Shares for 1 WBTC

useVaultWrite

Write operations: deposit, withdraw, redeem. Source: ~/workspace/source/src/hooks/use-vault-contract.ts:81
function useVaultWrite(vaultAddress: string, assetAddress: string): {
  deposit: (assets: bigint) => Promise<InvokeTransactionReceiptResponse>;
  withdraw: (assets: bigint) => Promise<InvokeTransactionReceiptResponse>;
  redeem: (shares: bigint) => Promise<InvokeTransactionReceiptResponse>;
}
Example:
const { deposit } = useVaultWrite(
  SABLE_CONTRACTS.SENTINEL,
  TOKENS.WBTC.address
);

// Deposit 0.5 WBTC
await deposit(BigInt(50000000));
Note: deposit() automatically approves WBTC spending and calls vault.deposit() in a multicall.

useStrategyInfo

Read leverage strategy details (collateral, debt, loops). Source: ~/workspace/source/src/hooks/use-vault-contract.ts:151
function useStrategyInfo(vaultAddress: string | null): {
  collateral: number;
  debt: number;
  loops: number;
  paused: boolean;
} | null

Shielded Vault Hooks

useShieldedDeposit

Deposit WBTC to a shielded pool with privacy. Source: ~/workspace/source/src/hooks/use-shielded-vault.ts:219
function useShieldedDeposit(poolAddress: string | null | undefined): {
  deposit: (
    denominationKey: string,
    denomination: bigint
  ) => Promise<{ note: ShieldedNote | null; error: string | null }>;
  pending: boolean;
  status: string;
  error: string | null;
}
Example:
import { useShieldedDeposit } from '@/hooks/use-shielded-vault';
import { SHIELDED_POOLS_V4 } from '@/lib/constants';

function PrivateDeposit() {
  const pool = SHIELDED_POOLS_V4.sentinel_1x;
  const { deposit, pending, status, error } = useShieldedDeposit(pool.pool);
  
  const handleDeposit = async () => {
    const { note, error } = await deposit('sentinel_1x', pool.denomination);
    if (note) {
      console.log('Note generated:', note.commitment);
      console.log('Store this note to withdraw later!');
    }
  };
  
  return (
    <div>
      <button onClick={handleDeposit} disabled={pending}>
        {status || 'Deposit 0.0002 BTC Privately'}
      </button>
      {error && <p>Error: {error}</p>}
    </div>
  );
}
Process:
  1. Generate note (commitment, nullifier, secret)
  2. User approves WBTC spending (wallet signature)
  3. Relayer submits pool.deposit(commitment, depositor)
  4. Note is saved to localStorage
  5. Returns ShieldedNote for later withdrawal

useShieldedWithdraw

Withdraw WBTC privately using a zero-knowledge proof. Source: ~/workspace/source/src/hooks/use-shielded-vault.ts:297
function useShieldedWithdraw(poolAddress: string | null | undefined): {
  withdraw: (
    note: ShieldedNote,
    recipient: string,
    depositEvents: Array<{ commitment: string; leafIndex: number }>
  ) => Promise<string | null>;
  pending: boolean;
  status: string;
  error: string | null;
  feeInfo: { feeSats: number; totalGasUsd: number } | null;
}
Example:
const { withdraw, pending, status, feeInfo } = useShieldedWithdraw(poolAddress);
const { events } = useDepositEvents(poolAddress);

const handleWithdraw = async (note: ShieldedNote) => {
  const recipientAddr = '0x...';
  const txHash = await withdraw(note, recipientAddr, events);
  if (txHash) {
    console.log('Withdrawal tx:', txHash);
    console.log('Note has been spent and marked as used');
  }
};
Process:
  1. Estimate relayer fee (~$0.01-0.05 in BTC)
  2. Build Merkle proof from deposit events
  3. Generate Groth16 ZK proof (10-30 seconds)
  4. Serialize proof to calldata
  5. Submit via relayer API
  6. Mark note as spent
Public Inputs: [root, nullifierHash, recipient, relayer, fee, batchStart, batchSize]

useShieldedBalance

Get unspent notes and total private balance. Source: ~/workspace/source/src/hooks/use-shielded-vault.ts:392
function useShieldedBalance(
  poolAddress: string | null | undefined,
  denominationKey?: string
): {
  notes: ShieldedNote[];
  noteCount: number;
  totalWbtc: bigint;
}

useSyncNotes

Sync note leaf indices and batch info from on-chain events. Source: ~/workspace/source/src/hooks/use-shielded-vault.ts:414
function useSyncNotes(
  poolAddress: string | null | undefined,
  fromBlock?: number
): {
  syncVersion: number;
}
Usage:
const { syncVersion } = useSyncNotes(poolAddress);

// syncVersion increments when notes are updated
// Use it as a dependency to trigger re-renders
useEffect(() => {
  const notes = loadNotes();
  console.log('Notes synced:', notes);
}, [syncVersion]);

DCA Hooks

useDcaOrders

Manage DCA orders: create, cancel, and fetch user orders. Source: ~/workspace/source/src/hooks/use-dca.ts:250
function useDcaOrders(): {
  orders: DcaOrder[];
  activeOrders: DcaOrder[];
  loading: boolean;
  createOrder: (params: {
    sellToken: string;
    sellAmountHuman: string;
    frequency: DcaFrequency;
    totalOrders: number;
    smart: boolean;
  }) => Promise<void>;
  cancelOrder: (orderId: number) => Promise<void>;
  refreshOrders: () => Promise<void>;
  txStep: DcaStep;
  txHash: string | null;
  txError: string | null;
  resetTx: () => void;
}
Example:
import { useDcaOrders, TOKENS } from '@/hooks/use-dca';

function DcaManager() {
  const { orders, createOrder, cancelOrder, txStep, txHash } = useDcaOrders();
  
  const handleCreate = async () => {
    await createOrder({
      sellToken: TOKENS.USDC.address,
      sellAmountHuman: '100', // 100 USDC per order
      frequency: 'weekly',
      totalOrders: 10,
      smart: true, // Enable Smart DCA (Mayer Multiple)
    });
  };
  
  return (
    <div>
      <button onClick={handleCreate}>Create Weekly DCA</button>
      {txStep === 'pending' && <p>Transaction pending: {txHash}</p>}
      
      <h3>Active Orders</h3>
      {orders.map(order => (
        <div key={order.id}>
          <p>Order #{order.id}: {order.executedOrders}/{order.totalOrders} executed</p>
          <p>Next: {new Date(order.nextExecution * 1000).toLocaleString()}</p>
          <button onClick={() => cancelOrder(order.id)}>Cancel</button>
        </div>
      ))}
    </div>
  );
}
DCA Types:
type DcaFrequency = 'daily' | 'weekly' | 'biweekly' | 'monthly';

interface DcaOrder {
  id: number;
  owner: string;
  sellToken: string;
  sellAmountPer: bigint;
  frequency: number; // seconds
  totalOrders: number;
  executedOrders: number;
  nextExecution: number; // unix timestamp
  active: boolean;
  smart: boolean; // Mayer Multiple enabled
  deposited: bigint;
  spent: bigint;
  btcReceived: bigint;
}

useMayerMultiple

Read current Mayer Multiple indicator for Smart DCA. Source: ~/workspace/source/src/hooks/use-dca.ts:181
function useMayerMultiple(): {
  data: MayerMultipleData | null;
  loading: boolean;
}

interface MayerMultipleData {
  spot: number; // Current BTC price
  twap200d: number; // 200-day TWAP
  mayerMultiple: number; // spot / twap200d
  band: string; // "Very Cheap" | "Below Average" | "Normal" | "Expensive" | "Overheated"
  multiplier: number; // 0.5, 0.75, 1.0, 1.25, or 1.5
}
Example:
const { data, loading } = useMayerMultiple();

if (!loading && data) {
  console.log(`BTC is ${data.band} (${data.mayerMultiple.toFixed(2)}x MA)`);
  console.log(`Smart DCA will buy ${data.multiplier}x the normal amount`);
}

CDP Hooks

useCdpPosition

Read user’s CDP collateral, debt, and health factor. Source: ~/workspace/source/src/hooks/use-cdp.ts:14
function useCdpPosition(): {
  position: {
    collateral: bigint; // WBTC sats
    debt: bigint; // USDC cents
    healthBps: bigint; // Health factor in basis points
    maxBorrow: bigint; // Max additional USDC borrowable
  } | null;
  loading: boolean;
}
Example:
const { position, loading } = useCdpPosition();

if (!loading && position) {
  const collateralBtc = Number(position.collateral) / 1e8;
  const debtUsdc = Number(position.debt) / 1e6;
  const healthFactor = Number(position.healthBps) / 10000;
  
  console.log(`Collateral: ${collateralBtc} BTC`);
  console.log(`Debt: ${debtUsdc} USDC`);
  console.log(`Health: ${healthFactor.toFixed(2)}x`);
}

useCdpActions

Deposit collateral, borrow USDC, repay, and withdraw. Source: ~/workspace/source/src/hooks/use-cdp.ts:115
function useCdpActions(): {
  depositAndBorrow: (
    wbtcAmount: bigint,
    usdcBorrowAmount: bigint
  ) => Promise<string | null>;
  repayAndWithdraw: (
    usdcRepayAmount: bigint,
    wbtcWithdrawAmount: bigint,
    fullRepay?: boolean
  ) => Promise<string | null>;
  closePosition: (usdcApproveAmount: bigint) => Promise<string | null>;
  pending: boolean;
  status: string;
  error: string | null;
}
Example:
const { depositAndBorrow, repayAndWithdraw, pending, status } = useCdpActions();

// Deposit 0.1 BTC and borrow 5000 USDC
await depositAndBorrow(
  BigInt(10000000), // 0.1 BTC = 10M sats
  BigInt(5000000000) // 5000 USDC = 5B cents
);

// Repay 2500 USDC and withdraw 0.05 BTC
await repayAndWithdraw(
  BigInt(2500000000),
  BigInt(5000000)
);

// Close position entirely (repay all debt, withdraw all collateral)
await closePosition(BigInt(5500000000)); // Approve slightly more for interest

Staking Hooks

useStakingPools

Fetch Vesu lending pool data with APYs. Source: ~/workspace/source/src/hooks/use-staking.ts:81
function useStakingPools(): {
  pools: StakingPoolData[];
  loading: boolean;
  error: string | null;
  refresh: () => Promise<void>;
}

interface StakingPoolData {
  config: StakingPoolConfig;
  supplyApy: number;
  btcFiApr: number;
  totalApy: number;
  utilization: number;
  tvlUsd: number;
  totalSuppliedBtc: number;
  btcPrice: number;
  borrowApr: number;
}

useVesuDeposit / useVesuWithdraw

Deposit to or withdraw from Vesu pools. Source: ~/workspace/source/src/hooks/use-staking.ts:188
function useVesuDeposit(poolId: string): {
  deposit: (amount: bigint) => Promise<InvokeTransactionReceiptResponse>;
}

function useVesuWithdraw(poolId: string): {
  withdraw: (amount: bigint) => Promise<InvokeTransactionReceiptResponse>;
}
Example:
import { useVesuDeposit, VESU_POOLS } from '@/hooks/use-staking';

function VesuStaking() {
  const { deposit } = useVesuDeposit(VESU_POOLS.PRIME.id);
  
  const handleDeposit = async () => {
    await deposit(BigInt(50000000)); // Deposit 0.5 BTC
    console.log('Received vWBTC shares');
  };
  
  return <button onClick={handleDeposit}>Stake to Vesu PRIME</button>;
}

Bridge Hooks

useBridge

Manage cross-chain bridge operations (1Click protocol). Source: ~/workspace/source/src/hooks/use-bridge.ts:90
function useBridge(): {
  state: BridgeState;
  tokens: OneClickToken[];
  chains: ChainInfo[];
  sourceTokens: OneClickToken[];
  destTokens: OneClickToken[];
  setDirection: (dir: 'in' | 'out') => void;
  setSourceChain: (chain: string) => void;
  setSourceToken: (token: OneClickToken) => void;
  setAmount: (amount: string) => void;
  setDestAddress: (addr: string) => void;
  setRefundAddress: (addr: string) => void;
  startBridgeIn: () => Promise<void>;
  startBridgeOut: () => Promise<void>;
  reset: () => void;
}
Example:
import { useBridge } from '@/hooks/use-bridge';

function Bridge() {
  const {
    state,
    chains,
    sourceTokens,
    setDirection,
    setSourceChain,
    setSourceToken,
    setAmount,
    setDestAddress,
    startBridgeIn,
  } = useBridge();
  
  const handleBridge = async () => {
    setDirection('in'); // Bridge to Starknet
    setSourceChain('Ethereum');
    setSourceToken(sourceTokens.find(t => t.symbol === 'USDC'));
    setAmount('100');
    setDestAddress('0x...');
    
    await startBridgeIn();
    console.log('Deposit address:', state.depositAddress);
  };
  
  return (
    <div>
      <button onClick={handleBridge}>Bridge 100 USDC to Starknet</button>
      {state.step === 'awaiting-deposit' && (
        <p>Send funds to: {state.depositAddress}</p>
      )}
      {state.step === 'complete' && <p>Bridge complete!</p>}
    </div>
  );
}
Bridge Steps:
  • idle: Form input
  • quoting: Fetching quote
  • quoted: Quote ready
  • awaiting-deposit: Waiting for user to send funds (bridge IN)
  • awaiting-transfer: User signing wallet (bridge OUT)
  • awaiting-1click: 1Click processing
  • complete: Bridge finished

Private Swap Hooks

usePrivateSwap

Execute private token swaps from WBTC pools to other tokens via AVNU. Source: ~/workspace/source/src/hooks/use-private-swap.ts
function usePrivateSwap(): {
  executePrivateSwap: (params: {
    sourceNote: ShieldedNote;
    sourcePoolId: string;
    outputToken: string;
    recipient: string;
    slippage?: number;
  }) => Promise<{ txHash: string; leafIndex: number; outputAmount: string }>;
  loading: boolean;
  error: string | null;
}
Example:
import { usePrivateSwap } from '@/hooks/use-private-swap';
import { getUnspentNotesByVaultId } from '@/lib/privacy/note';

function PrivateSwap() {
  const { executePrivateSwap, loading, error } = usePrivateSwap();
  
  const handleSwap = async () => {
    const notes = getUnspentNotesByVaultId('swap_1x');
    if (notes.length === 0) {
      alert('No unspent notes in swap pool');
      return;
    }
    
    const result = await executePrivateSwap({
      sourceNote: notes[0],
      sourcePoolId: 'swap_1x',
      outputToken: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7', // ETH
      recipient: '0x...',
      slippage: 0.02, // 2%
    });
    
    console.log('Swap TX:', result.txHash);
    console.log('Received:', result.outputAmount);
  };
  
  return (
    <div>
      <button onClick={handleSwap} disabled={loading}>
        {loading ? 'Swapping...' : 'Private Swap WBTC → ETH'}
      </button>
      {error && <p style={{ color: 'red' }}>{error}</p>}
    </div>
  );
}
Private swaps generate a Groth16 proof client-side, then submit to /api/relayer/private-swap which verifies the proof, withdraws WBTC from the source pool, swaps via AVNU, and deposits the output token to the recipient.

useSwapPoolEvents

Fetch all swap deposit events from the shielded swap pool. Source: ~/workspace/source/src/hooks/use-private-swap.ts:25
function useSwapPoolEvents(): {
  events: Array<{
    commitment: string;
    leafIndex: number;
    outputToken: string;
    outputAmount: string;
  }>;
  loading: boolean;
}
Example:
import { useSwapPoolEvents } from '@/hooks/use-private-swap';

function SwapHistory() {
  const { events, loading } = useSwapPoolEvents();
  
  if (loading) return <p>Loading swap history...</p>;
  
  return (
    <ul>
      {events.map((evt, i) => (
        <li key={i}>
          Leaf {evt.leafIndex}: {evt.outputAmount} of token {evt.outputToken}
        </li>
      ))}
    </ul>
  );
}

Build docs developers (and LLMs) love