> For the complete documentation index, see [llms.txt](https://gotts.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gotts.gitbook.io/docs/gotts-vaults/vault/07-sdk.md).

# TypeScript SDK

> **Part of**: [Vault PRD](/docs/gotts-vaults/vault.md) | **Last Updated**: 2026-02-13

***

## TypeScript SDK

The SDK provides 9 core classes for vault interaction, published as `@gotts.ai/vault`.

### 11.0 UniswapApiClient

Wraps all Uniswap Trading API calls with retry, rate limiting, and quote freshness tracking. When `GOTTS_UNISWAP_API_KEY` is not configured, all methods throw `API_KEY_NOT_CONFIGURED`.

```typescript
class UniswapApiClient {
  constructor(config: {
    apiKey: string;
    baseUrl?: string;
    rateLimitPerSec?: number;
  });

  // === Swap Operations ===

  /** Check if token approval is needed for the swap */
  async checkApproval(params: {
    token: Address;
    amount: string;
    chainId: number;
  }): Promise<ApprovalResponse>;

  /** Get optimized quote across V2/V3/V4/UniswapX */
  async getQuote(params: QuoteRequest): Promise<QuoteResponse>;

  /** Get executable swap transaction (for CLASSIC/WRAP/UNWRAP/BRIDGE routing) */
  async getSwapTransaction(params: {
    quote: QuoteResponse;
    signature?: string;
    permitData?: PermitData;
  }): Promise<TransactionRequest>;

  /** Submit gasless order (for DUTCH_V2/DUTCH_V3/PRIORITY routing) */
  async submitOrder(params: {
    quote: QuoteResponse;
    signature: string;
  }): Promise<OrderResponse>;

  // === LP Operations ===

  /** Check and approve both tokens for LP, returns batchPermitData */
  async lpApprove(params: LpApproveRequest): Promise<LpApproveResponse>;

  /** Create a new LP position */
  async lpCreate(params: LpCreateRequest): Promise<LpCreateResponse>;

  /** Increase liquidity in an existing position */
  async lpIncrease(params: LpIncreaseRequest): Promise<LpIncreaseResponse>;

  /** Decrease liquidity (partial or full removal) */
  async lpDecrease(params: LpDecreaseRequest): Promise<LpDecreaseResponse>;

  /** Collect accrued fees from a position */
  async lpClaim(params: LpClaimRequest): Promise<LpClaimResponse>;

  /** Migrate a V3 position to V4 */
  async lpMigrate(params: LpMigrateRequest): Promise<LpMigrateResponse>;

  /** Claim LP incentive rewards */
  async lpClaimRewards(
    params: LpClaimRewardsRequest,
  ): Promise<LpClaimRewardsResponse>;
}

interface QuoteRequest {
  tokenIn: Address;
  tokenOut: Address;
  tokenInChainId: number;
  tokenOutChainId: number;
  amount: string;
  type: "EXACT_INPUT" | "EXACT_OUTPUT";
  swapper: Address;
  slippageTolerance?: number;
  protocols?: string[]; // e.g., ["V4","V3","V2","UNISWAPX_V2"]
}

interface QuoteResponse {
  routing:
    | "CLASSIC"
    | "DUTCH_V2"
    | "DUTCH_V3"
    | "PRIORITY"
    | "WRAP"
    | "UNWRAP"
    | "BRIDGE";
  quote: string;
  quoteGasAdjusted: string;
  gasFeeUSD: string;
  priceImpact: number;
  permitData?: PermitData;
  requestId: string;
}
```

**Required headers for all API calls**:

* `x-api-key`: The API key
* `Content-Type: application/json`
* `x-universal-router-version: 2.0`

**Rate limiting**: Configurable via `GOTTS_UNISWAP_API_RATE_LIMIT` (default 3 req/sec). Uses token bucket algorithm with exponential backoff on 429 responses.

***

### 11.1 VaultFactoryClient

Create, list, and discover vaults deployed through the AgentVaultFactory.

```typescript
class VaultFactoryClient {
  constructor(config: FactoryClientConfig);

  // === Factory Operations ===

  /** Deploy a new vault via the factory. Caller must be ERC-8004 registered. */
  async createVault(params: CreateVaultParams): Promise<CreateVaultResult>;

  /** List all vaults in the factory registry */
  async listVaults(filter?: VaultFilter): Promise<VaultInfo[]>;

  /** Get all vaults created by a specific agent */
  async getVaultsByCreator(agentId: string): Promise<Address[]>;

  /** Get full vault configuration */
  async getVaultConfig(vaultAddress: Address): Promise<VaultConfig>;

  /** Total number of vaults deployed */
  async vaultCount(): Promise<number>;

  /** Check if an address is a factory-deployed vault */
  async isVault(address: Address): Promise<boolean>;
}

interface CreateVaultParams {
  agentId: string;
  baseAsset: Address;
  managementFeeBps?: number; // default: 100 (1%)
  performanceFeeBps?: number; // default: 1000 (10%)
  minReputation?: number; // default: 0 (open)
  ccaEnabled?: boolean; // default: false
  hookEnabled?: boolean; // default: false
  hookConfig?: HookConfig;
  metadataURI?: string;
  template?:
    | "simple-yield"
    | "cca-hunter"
    | "lp-manager"
    | "full-stack"
    | "meta-vault";

  // V4 auto-market configuration
  autoPoolEnabled?: boolean; // default: true when hookEnabled
  navSpreadBps?: number; // default: 50 (0.50%)
  launchFeeEnabled?: boolean; // default: true
  launchFeeMaxBps?: number; // default: 8000 (80%)
  launchFeeDecaySeconds?: number; // default: 120
  rehypothecationEnabled?: boolean; // default: false (opt-in)
}

interface CreateVaultResult {
  vaultAddress: Address;
  hookAddress: Address;
  sharePoolAddress: Address; // V4 pool for share token (zero if autoPoolEnabled=false)
  sharePoolId: string; // V4 PoolId
  txHash: Hash;
  explorerUrl: string;
}

interface VaultFilter {
  creator?: string; // Filter by creator agent ID
  baseAsset?: Address; // Filter by base asset
  minTvl?: string; // Minimum TVL
  ccaEnabled?: boolean; // Only CCA-enabled vaults
  sortBy?: "tvl" | "performance" | "sharpe" | "created";
}
```

### 11.2 VaultClient

Full vault interaction wrapper. Supports connecting to any factory-deployed vault by address.

```typescript
class VaultClient {
  constructor(config: VaultClientConfig);

  // === Deposits and Withdrawals ===
  async deposit(agentId: string, amount: string): Promise<DepositResult>;
  async withdraw(
    agentId: string,
    amount: string | "max",
  ): Promise<WithdrawResult>;
  async simulateDeposit(
    agentId: string,
    amount: string,
  ): Promise<SimulationResult>;

  // === Read Operations ===
  async getState(): Promise<VaultState>;
  async getPositions(): Promise<Position[]>;
  async getAgentShares(agentId: string): Promise<AgentShareInfo>;
  async getPerformance(period?: string): Promise<PerformanceMetrics>;
  async getRiskMetrics(): Promise<RiskMetrics>;
  async getStrategy(): Promise<StrategyInfo>;

  // === Manager Operations ===
  async rebalance(
    agentId: string,
    params?: RebalanceParams,
  ): Promise<RebalanceResult>;
  async collectFees(positionIds?: string): Promise<CollectResult>;
  async deployLiquidity(
    pool: Address,
    params: DeployParams,
  ): Promise<DeployResult>;

  // === API-Powered Operations (use Uniswap Trading API when available) ===
  /** Collect fees from all vault positions. Uses /lp/claim for each position when API key available. */
  async collectAllFees(): Promise<CollectAllResult>;
  /** Emergency full withdrawal: decrease all positions 100%, claim fees, swap all to target stable */
  async emergencyExit(targetStable: Address): Promise<EmergencyExitResult>;

  // === TWAMM Rebalancing (large vault operations) ===
  /** Rebalance using TWAMM to minimize price impact for large operations */
  async rebalanceViaTWAMM(
    agentId: string,
    params: TWAMMRebalanceParams,
  ): Promise<TWAMMRebalanceResult>;

  // === Rehypothecation Management (opt-in) ===
  /** Enable rehypothecation of idle out-of-range liquidity */
  async enableRehypothecation(
    params: RehypothecationConfig,
  ): Promise<EnableResult>;
  /** Get current rehypothecation status and lending positions */
  async getRehypothecationStatus(): Promise<RehypothecationStatus>;
  /** Emergency withdrawal from all lending venues */
  async emergencyWithdrawLending(): Promise<WithdrawResult>;

  // === Agent Registration ===
  async registerAgent(agentId: string): Promise<RegisterResult>;
}
```

### Exit Mode Display (Normative)

The SDK MUST surface vault exit mode information so agents and UIs can present clear expectations. This applies to both `VaultClient` and any higher-level UI layer.

**Required behavior**:

* The SDK MUST read the vault's `vaultCapabilities()` bitmap (see [06-contracts.md](/docs/gotts-vaults/vault/06-contracts.md) Vault Interaction Safety) and display the exit mode:
  * **Instant exit** (synchronous): `withdraw()` / `redeem()` execute immediately
  * **Queued exit** (async request/claim): Display ETA range and queue position via `claimableRedeemRequest()`
* All `deposit()` and `withdraw()` methods MUST accept optional slippage parameters:
  * `deposit(agentId, amount, { maxAssetsIn })` -- revert if actual cost exceeds `maxAssetsIn`
  * `withdraw(agentId, amount, { minAssetsOut })` -- revert if received assets are below `minAssetsOut`
* If a vault supports both sync and async paths, the SDK MUST expose both and recommend the optimal path based on current queue depth, gas costs, and share pool pricing.

```typescript
interface ExitModeInfo {
  mode: "instant" | "queued" | "hybrid";
  estimatedWaitSeconds?: number;
  queuePosition?: number;
  queueDepth?: number;
  sharePoolAlternative?: {
    available: boolean;
    priceVsNav: number; // 1.0 = at NAV, >1.0 = premium, <1.0 = discount
    estimatedSlippageBps: number;
  };
}

interface SlippageParams {
  maxAssetsIn?: string; // For deposits: max assets to spend
  minAssetsOut?: string; // For withdrawals: min assets to receive
  maxSlippageBps?: number; // Convenience: auto-compute from preview
}
```

> **References**: EIP-5143 (slippage protection concepts), EIP-7540 (async vault standard), Lido withdrawal queue UX (receipt + ETA pattern).

***

### 11.3 StrategyEngine

Volatility analysis, rebalance recommendations, and APY estimation.

```typescript
class StrategyEngine {
  /** Analyze current pool state and recommend optimal strategy */
  async analyzeAndRecommend(
    vaultAddress: Address,
  ): Promise<StrategyRecommendation>;

  /** Calculate optimal rebalance parameters based on tick history */
  async calculateRebalance(positions: Position[]): Promise<RebalanceParams>;

  /** Estimate APY from historical fee data */
  async estimateAPY(
    vaultAddress: Address,
    period?: number,
  ): Promise<APYEstimate>;

  /** Evaluate volatility from tick history */
  async getVolatilityMetrics(poolId: string): Promise<VolatilityMetrics>;

  /** Recommend TWAMM vs immediate swap based on rebalance size vs pool liquidity.
   *  Returns useTWAMM=true when rebalance exceeds 1% of pool TVL. */
  async recommendTWAMM(
    rebalanceSize: string,
    poolAddress: Address,
  ): Promise<TWAMMRecommendation>;

  /** Estimate additional yield from rehypothecation of idle out-of-range liquidity */
  async estimateRehypothecationYield(
    vaultAddress: Address,
  ): Promise<RehypothecationEstimate>;

  // === API-Powered Operations ===

  /** Rebalance vault via Uniswap API: /quote + /swap for swaps, /lp/* for position adjustments */
  async rebalanceViaApi(
    vaultAddress: Address,
    params: RebalanceParams,
  ): Promise<RebalanceResult>;

  /** Collect all fees via API: iterates vault positions, calls /lp/claim for each */
  async collectAllFeesViaApi(vaultAddress: Address): Promise<CollectAllResult>;

  /** Migrate all V3 positions to V4 via API: calls /lp/migrate for each V3 position */
  async migratePositionsToV4(
    vaultAddress: Address,
    positionIds?: string[],
  ): Promise<MigrateResult[]>;
}

interface TWAMMRecommendation {
  useTWAMM: boolean;
  reason: string;
  suggestedDurationSeconds: number;
  estimatedSlippageBps: number; // With TWAMM
  immediateSlippageBps: number; // Without TWAMM
  savingsUsd: string; // Estimated savings from using TWAMM
}

interface RehypothecationEstimate {
  idleLiquidityUsd: string; // Total out-of-range liquidity available
  estimatedAnnualYieldBps: number; // Additional APY from lending
  recommendedVenues: Array<{
    venue: string;
    apyBps: number;
    allocationPct: number;
  }>;
  riskFactors: string[];
}
```

### 11.4 CCABidder

CCA auction evaluation and bid lifecycle management. New class for the factory architecture.

```typescript
class CCABidder {
  /** List available CCA auctions with quality assessment */
  async getAvailableAuctions(): Promise<AuctionInfo[]>;

  /** Evaluate a specific auction: graduation likelihood, token quality, pricing */
  async evaluateAuction(auctionAddress: Address): Promise<AuctionEvaluation>;

  /** Submit a collective bid through the vault's CCA adapter */
  async submitBid(params: BidParams): Promise<BidResult>;

  /** Exit a bid (completed, outbid, or partially filled) */
  async exitBid(auction: Address, bidId: string): Promise<ExitResult>;

  /** Claim tokens after auction graduation */
  async claimTokens(auction: Address, bidId: string): Promise<ClaimResult>;

  /** Deploy claimed tokens as V4 LP via the vault */
  async deployToPool(
    auction: Address,
    bidId: string,
    params: DeployParams,
  ): Promise<DeployResult>;

  /** Get all active bids across all vaults */
  async getActiveBids(vaultAddress?: Address): Promise<BidPosition[]>;
}

interface BidParams {
  vaultAddress: Address;
  auctionAddress: Address;
  amount: string; // USDC amount to bid
  maxPrice: string; // Maximum price willing to pay
  prevTickPrice?: string; // Hint for gas-efficient insertion
}

interface AuctionEvaluation {
  auctionAddress: Address;
  tokenAddress: Address;
  tokenName: string;
  graduationLikelihood: "high" | "medium" | "low";
  currentRaised: string;
  requiredRaised: string;
  percentageToGraduation: number;
  floorPrice: string;
  currentClearingPrice: string;
  bidVelocity: string; // Bids per block
  riskFactors: string[];
  recommendation: "bid" | "watch" | "avoid";
}
```

### 11.5 HookDeployer

HookMiner + CREATE2 deployment for VaultHook.

```typescript
class HookDeployer {
  /** Find a valid hook address with required permission flags */
  async findHookAddress(
    params: HookParams,
  ): Promise<{ address: Address; salt: Hex }>;

  /** Deploy VaultHook at the mined address */
  async deployHook(params: HookParams, salt: Hex): Promise<DeployHookResult>;

  /** Initialize a V4 pool with the deployed hook */
  async initializePool(
    hookAddress: Address,
    poolParams: PoolParams,
  ): Promise<PoolId>;
}
```

### 11.6 x402Gateway

Express middleware for x402-gated strategy endpoints.

```typescript
class x402Gateway {
  /** Create Express middleware for x402-gated vault analytics */
  createMiddleware(): ExpressMiddleware;

  /** Get pricing for all endpoints */
  getPricing(): EndpointPricing;

  /** Verify x402 payment and check payer is a registered agent */
  async verifyPayment(payment: x402Payment): Promise<VerifyResult>;
}
```

Six strategy endpoints with tiered pricing:

| Endpoint                   | Price  | Description                                            |
| -------------------------- | ------ | ------------------------------------------------------ |
| `/strategy/volatility`     | $0.005 | Current volatility metrics for vault's pools           |
| `/strategy/rebalance`      | $0.01  | Rebalance recommendation with parameters               |
| `/strategy/apy-estimate`   | $0.005 | APY estimate based on historical data                  |
| `/strategy/risk-analysis`  | $0.01  | Position risk assessment                               |
| `/strategy/cca-evaluation` | $0.05  | CCA auction evaluation and bid recommendation          |
| `/strategy/full-analysis`  | $0.10  | Combined analysis: volatility + APY + risk + rebalance |

### 11.7 ReputationReader

ERC-8004 reputation queries and tier mapping. New class for the factory architecture.

```typescript
class ReputationReader {
  /** Get an agent's reputation summary from the ERC-8004 Reputation Registry */
  async getReputation(agentId: string): Promise<ReputationSummary>;

  /** Map a reputation score to a protocol tier */
  getTier(score: number): AgentTier;

  /** Get tier limits for a specific tier */
  getTierLimits(tier: AgentTier): TierLimits;

  /** Check if an agent meets a vault's minimum reputation requirement */
  async meetsVaultRequirements(
    agentId: string,
    vaultAddress: Address,
  ): Promise<boolean>;

  /** Get all feedback for an agent (optionally filtered by tag) */
  async getFeedback(agentId: string, tag?: string): Promise<FeedbackEntry[]>;
}

type AgentTier = "unverified" | "basic" | "verified" | "trusted" | "sovereign";

interface TierLimits {
  maxDepositUsd: number;
  maxRebalancesPerDay: number;
  maxDailyAggregateUsd: number;
  managementFeeDiscount: number; // percentage
  performanceFeeDiscount: number; // percentage
}
```

### 11.7a Agent0 SDK Integration (D-080, D-081)

Wrapper module for the Agent0 SDK (`@agent0/sdk`), providing ERC-8004 identity registration, yield feedback submission, and agent discovery for AgenticVaults participants. Uses Privy agentic wallets (`@privy-io/node`) for key management.

**Dependencies**: `@agent0/sdk`, `@privy-io/node`, `@privy-io/node/viem`, `viem`

```typescript
class Agent0Integration {
  /** Initialize with Privy-backed EIP-1193 provider.
   *  Two paths:
   *  - Path A (production): existing wallet via env vars (deterministic)
   *  - Path B (onboarding): auto-create wallet on first run */
  constructor(config: Agent0Config);

  /** Register a vault manager as an ERC-8004 agent.
   *  Sets on-chain metadata (role, protocol, chain, vaultAddress, asset, strategyType).
   *  Uploads registration file to IPFS with MCP/A2A/OASF services array.
   *  Mints agent NFT on-chain via Privy enclave signing. */
  async registerVaultManager(
    params: VaultManagerRegistration,
  ): Promise<RegistrationResult>;

  /** Register an investor agent */
  async registerInvestor(
    params: InvestorRegistration,
  ): Promise<RegistrationResult>;

  /** Submit automated yield feedback (per-epoch).
   *  Computes yield from share price delta, prepares feedbackURI with risk metrics,
   *  submits to ERC-8004 Reputation Registry via giveFeedback(). */
  async submitYieldFeedback(
    params: YieldFeedbackParams,
  ): Promise<FeedbackResult>;

  /** Submit qualitative feedback from an investor to a vault manager */
  async submitQualitativeFeedback(
    params: QualitativeFeedbackParams,
  ): Promise<FeedbackResult>;

  /** Search for vault managers by OASF domain, chain, and reputation.
   *  Uses Agent0 SDK searchAgents() + searchAgentsByReputation(). */
  async discoverVaultManagers(
    params: DiscoveryParams,
  ): Promise<DiscoveredAgent[]>;

  /** Get yield feedback history for an agent (from Reputation Registry) */
  async getYieldFeedback(
    agentId: string,
    tag?: string,
  ): Promise<FeedbackEntry[]>;

  /** Get aggregated reputation summary */
  async getReputationSummary(agentId: string): Promise<ReputationSummary>;
}

interface Agent0Config {
  chainId: number;
  rpcUrl: string;
  /** Privy wallet config -- signing key stays in Privy enclave */
  privy: {
    appId: string;
    appSecret: string;
    walletId: string;
    walletAddress: string;
    authorizationPrivateKey: string; // P-256 key (NOT the Ethereum signing key)
  };
  /** IPFS provider for registration file upload */
  ipfs: "pinata" | "filecoin";
  pinataJwt?: string;
}

interface VaultManagerRegistration {
  name: string;
  description: string;
  vaultAddress: string;
  asset: string;
  strategyType: string;
  mcpEndpoint: string;
  a2aEndpoint?: string;
  oasfDomains?: string[];
  feePerformanceBps?: number;
  feeManagementBps?: number;
}

interface DiscoveryParams {
  chain?: number;
  asset?: string;
  minReputationScore?: number;
  minFeedbackCount?: number;
  oasfDomains?: string[];
  active?: boolean;
}

interface DiscoveredAgent {
  agentId: string;
  name: string;
  vaultAddress?: string;
  asset?: string;
  mcpEndpoint?: string;
  a2aEndpoint?: string;
  reputationTier: string;
  averageYield?: number;
  sharpeRatio?: number;
}
```

**Key Security Properties** (D-081, D-088):

* **Signing key isolation**: The Ethereum private key lives in Privy's secure enclave. The server only holds the P-256 authorization key, which authorizes signing requests but cannot extract the signing key.
* **EIP-712 support**: ERC-8004's `agentWallet` metadata verification requires EIP-712 signatures. Privy's enclave handles this natively.
* **Non-custodial default**: The MCP server prepares unsigned transactions and returns them to the agent. The agent signs via its own Privy wallet. Only when the server IS the vault manager agent does it hold keys (via Privy enclave).

### 11.8 SharePoolClient

Interact with auto-created V4 share pools — buy/sell vault shares via Uniswap as an alternative to direct vault deposit/withdraw. Enables instant exits and secondary market trading.

```typescript
class SharePoolClient {
  constructor(config: SharePoolClientConfig);

  /** Get the V4 pool for a vault's share token */
  async getSharePool(vaultAddress: Address): Promise<SharePoolInfo>;

  /** Get current NAV, pool price, and spread for a vault's shares */
  async getSharePoolPrice(vaultAddress: Address): Promise<SharePoolPrice>;

  /** Buy vault shares via the V4 pool (alternative to vault.deposit)
   *  Uses NAVAwareHook pricing — buys at NAV + buyFee (default 5 bps) */
  async buySharesViaPool(params: BuySharesParams): Promise<SwapResult>;

  /** Sell vault shares via the V4 pool (alternative to vault.withdraw)
   *  Uses NAVAwareHook pricing — sells at NAV - sellFee (default 25-50 bps)
   *  Instant execution, no withdrawal queue */
  async sellSharesViaPool(params: SellSharesParams): Promise<SwapResult>;

  /** Check NAV vs pool price for arbitrage detection.
   *  Returns discount/premium percentage and whether arb is profitable. */
  async getNAVDiscount(vaultAddress: Address): Promise<NAVDiscount>;

  /** List all share pools across the factory with NAV data */
  async listSharePools(filter?: SharePoolFilter): Promise<SharePoolInfo[]>;
}

interface SharePoolInfo {
  vaultAddress: Address;
  sharePoolAddress: Address;
  poolId: string;
  shareToken: Address;
  baseAsset: Address;
  navPerShare: string; // Current NAV from vault.convertToAssets(1e18)
  poolPrice: string; // Current price on V4 pool
  navSpreadBps: number; // Configured spread
  buyFeeBps: number; // Fee to buy shares (indirect deposit)
  sellFeeBps: number; // Fee to sell shares (indirect redeem)
  volume24h: string; // 24h trading volume on share pool
  launchFeeActive: boolean; // Whether descending launch fee is still active
}

interface SharePoolPrice {
  navPerShare: string;
  poolBuyPrice: string; // Price to buy shares (NAV + spread + buyFee)
  poolSellPrice: string; // Price to sell shares (NAV - spread - sellFee)
  discountPremiumBps: number; // Positive = premium, negative = discount
}

interface NAVDiscount {
  vaultAddress: Address;
  navPerShare: string;
  poolPrice: string;
  discountBps: number; // Positive = shares trade below NAV (buy opportunity)
  premiumBps: number; // Positive = shares trade above NAV (sell opportunity)
  arbProfitable: boolean; // After accounting for fees and gas
  estimatedArbProfitUsd: string;
}
```

**UX rationale**: The SharePoolClient is the key UX simplification for passive depositors. Instead of interacting with vault contracts directly, agents can trade vault shares like any other token on Uniswap. This reduces the mental model from "deposit into a vault" to "buy a yield-bearing token" — familiar to any DeFi agent.

***

### MemoryClient

Wraps both LanceDB (episodic) and SQLite/sqlite-vec (semantic) stores into a unified memory interface. Used by MCP tools and agents when the `learning` profile is active.

```typescript
interface EpisodeInput {
  tool: string;
  outcome: Record<string, unknown>;
  reflection: string;
  chain: string;
  tokenPair?: string;
  importance?: "routine" | "notable" | "critical" | "emergency";
}

interface Episode extends EpisodeInput {
  episodeId: string;
  vector: Float32Array;
  timestamp: number;
  consolidated: boolean;
}

interface InsightFilter {
  category?: InsightCategory;
  minConfidence?: number;
  maxConfidence?: number;
  chain?: string;
  tokenPair?: string;
  sortBy?: "confidence" | "recency" | "stability" | "accessCount";
  limit?: number;
}

type InsightCategory =
  | "slippage"
  | "gas_timing"
  | "route_selection"
  | "pool_behavior"
  | "mev_pattern"
  | "liquidity_depth"
  | "volatility"
  | "fee_optimization"
  | "rebalance_timing"
  | "vault_strategy"
  | "emergency"
  | "general";

interface Insight {
  insightId: string;
  content: string;
  category: InsightCategory;
  confidence: number;
  stability: number;
  retention: number;
  accessCount: number;
  chain?: string;
  tokenPair?: string;
  createdAt: number;
  lastAccessed: number;
}

interface MemoryContext {
  episodes: Array<Episode & { relevanceScore: number }>;
  insights: Array<Insight & { relevanceScore: number }>;
  adjustments: string[];
  queryEmbeddingMs: number;
}

interface ConsolidationReport {
  episodesProcessed: number;
  operations: {
    added: number;
    upvoted: number;
    downvoted: number;
    edited: number;
  };
  insightsArchived: number;
  decayPassResults: {
    insightsDecayed: number;
    belowThreshold: number;
    archived: number;
  };
  durationMs: number;
}

interface MemoryStats {
  episodic: { totalEpisodes: number; maxEpisodes: number; diskSizeMb: number };
  semantic: {
    totalInsights: number;
    activeInsights: number;
    archivedInsights: number;
    avgConfidence: number;
  };
  embedding: {
    model: string;
    dims: number;
    dtype: string;
    loaded: boolean;
    avgEmbedMs: number;
  };
  consolidation: { lastRun: number; nextScheduled: number; totalRuns: number };
}

class MemoryClient {
  constructor(config: MemoryConfig);

  // Episodic Memory (LanceDB)
  storeEpisode(input: EpisodeInput): Promise<{ episodeId: string }>;
  searchEpisodes(
    query: string,
    options?: {
      chain?: string;
      tokenPair?: string;
      tool?: string;
      limit?: number;
    },
  ): Promise<Array<Episode & { relevanceScore: number }>>;

  // Semantic Memory (SQLite/sqlite-vec)
  getInsights(filter?: InsightFilter): Promise<Insight[]>;
  addInsight(
    content: string,
    category: InsightCategory,
    options?: { chain?: string; tokenPair?: string },
  ): Promise<Insight>;
  upvoteInsight(insightId: string, reason?: string): Promise<Insight>;
  downvoteInsight(insightId: string, reason?: string): Promise<Insight>;
  editInsight(insightId: string, newContent: string): Promise<Insight>;

  // Context (single-call retrieve + format)
  getMemoryContext(
    toolName: string,
    params: Record<string, unknown>,
  ): Promise<MemoryContext>;

  // Consolidation (ExpeL)
  consolidate(options?: {
    maxEpisodes?: number;
    dryRun?: boolean;
  }): Promise<ConsolidationReport>;

  // Health
  getStats(): Promise<MemoryStats>;

  // Embedding
  embed(text: string): Promise<Float32Array>;
  embedBatch(texts: string[]): Promise<Float32Array[]>;

  // Lifecycle
  initialize(): Promise<void>;
  close(): Promise<void>;
}
```

**Key methods**:

* `getMemoryContext()` is the primary entry point for tool handlers — single call retrieves relevant episodes + insights, formats them, and returns adjustment recommendations
* `consolidate()` implements the ExpeL loop — normally called by the scheduled interval but available for manual invocation
* `embed()` and `embedBatch()` expose the Transformers.js embedding pipeline for custom use cases
* `initialize()` runs the startup sequence: SQLite → sqlite-vec → Drizzle migrations → LanceDB → schedule consolidation
* `close()` flushes pending writes, stops the consolidation scheduler, and releases resources

***

### 11.9 Utility Modules

Standalone utilities with no mcp-server dependency:

| Module                 | Location                          | Purpose                                                                         |
| ---------------------- | --------------------------------- | ------------------------------------------------------------------------------- |
| `ChainCapabilities`    | `utils/chain-capabilities.ts`     | Per-chain feature detection; see [shared/chains.md](/docs/prd-shared/chains.md) |
| `ChainProvider`        | `utils/chain-provider.ts`         | Minimal viem `PublicClient` factory                                             |
| `WalletInterface`      | `utils/wallet.ts`                 | Abstract wallet interface (local, Privy, Safe)                                  |
| `LRUCache`             | `utils/cache.ts`                  | Tiered TTL cache (15s/5min/1hr)                                                 |
| `VaultError`           | `utils/errors.ts`                 | `VAULT_*` error codes with structured messages                                  |
| `Formatters`           | `utils/formatters.ts`             | Human-readable amounts, explorer URLs                                           |
| `Safety`               | `utils/safety.ts`                 | Standalone or mcp-server peer safety pipeline                                   |
| `IdentityVerification` | `safety/identity-verification.ts` | ERC-8004 identity checks                                                        |
| `CrossChainIdentity`   | `safety/cross-chain-identity.ts`  | Ethereum -> Base identity resolution                                            |
| `VaultCircuitBreaker`  | `safety/vault-circuit-breaker.ts` | NAV monitoring and circuit breaker logic                                        |

***

### ChainCapabilities Type (Normative)

`VaultClientConfig` MUST include `chainId` and either inline `ChainCapabilities` or an on-chain registry lookup for them. Clients MUST NOT assume feature availability without checking capabilities.

```typescript
interface ChainCapabilities {
  v4SharePools: boolean;
  paymaster: boolean;
  subgraphV3: boolean;
  subgraphV4: boolean;
  erc7540: boolean;
  uniswapX: boolean;
  erc7683: boolean;
  erc8004Registry: "primary" | "read-only" | false;
}

interface VaultClientConfig {
  chainId: number;
  capabilities: ChainCapabilities; // or fetched from on-chain registry
  vaultAddress: Address;
  rpcUrl: string;
  walletConfig: WalletConfig;
}
```

See [shared/chains.md](/docs/prd-shared/chains.md) for the per-chain capability matrix and fallback behaviors.

***

## Proxy SDK (`packages/agent-proxy/sdk/`)

The following SDK classes belong to the standalone `packages/agent-proxy/` module, published as `@gotts.ai/agent-proxy`. They are independently usable with any agent wallet and do not depend on the vault protocol.

### 11.10 ProxyClient

Interact with deployed AgentProxy contracts -- announce transactions, execute after delay, cancel, and query state.

```typescript
class ProxyClient {
  constructor(config: ProxyClientConfig);

  /** Submit a time-delayed transaction announcement */
  async announce(params: AnnounceParams): Promise<AnnounceResult>;

  /** Execute a pending announcement after delay has elapsed */
  async execute(txId: bigint): Promise<ExecuteResult>;

  /** Cancel a pending announcement (requires CANCEL_ROLE) */
  async cancel(txId: bigint): Promise<CancelResult>;

  /** Batch cancel a range of announcements (emergency) */
  async cancelAll(fromId: bigint, toId: bigint): Promise<CancelResult>;

  /** Agent cancels their own pending announcement */
  async removeAnnouncement(txId: bigint): Promise<CancelResult>;

  /** List all pending announcements */
  async getPending(filter?: { agent?: Address }): Promise<Announcement[]>;

  /** Check if a specific announcement is executable */
  async isExecutable(txId: bigint): Promise<boolean>;

  /** Get agent's proxy configuration */
  async getAgentConfig(agent: Address): Promise<ProxyConfig>;

  /** Get all whitelisted calls for a proxy type */
  async getWhitelist(proxyType: ProxyType): Promise<WhitelistEntry[]>;
}

interface AnnounceParams {
  target: Address;
  value?: bigint;
  data: Hex;
}

interface AnnounceResult {
  txId: bigint;
  txHash: Hash;
  executeAfter: number; // unix timestamp
  expiration: number; // unix timestamp
  callHash: Hash;
}
```

### 11.11 MonitorBot

Event-driven monitoring bot that watches `TransactionAnnounced` events and evaluates them against configurable policies.

```typescript
class MonitorBot {
  constructor(config: MonitorBotConfig);

  /** Start monitoring proxy contracts for announcements */
  async start(): Promise<void>;

  /** Stop monitoring */
  async stop(): Promise<void>;

  /** Add a proxy contract to monitor */
  addProxy(proxyAddress: Address): void;

  /** Remove a proxy contract from monitoring */
  removeProxy(proxyAddress: Address): void;

  /** Configure the evaluation policy */
  setPolicy(policy: EvaluationPolicy): void;

  /** Get monitoring status */
  getStatus(): MonitorStatus;

  /** Get recent evaluation history */
  getHistory(limit?: number): EvaluationRecord[];
}

interface MonitorBotConfig {
  rpcProviders: string[]; // Multiple WebSocket URLs for redundancy
  cancelAuthority: CancelAuthority; // KMS-backed cancel key
  alertChannels: AlertChannel[]; // Telegram, Discord, PagerDuty
  policy: EvaluationPolicy;
  tenderlyConfig?: TenderlyConfig; // Optional simulation before cancel
}

interface EvaluationPolicy {
  whitelistedTargets: Address[];
  whitelistedSelectors: Record<Address, Hex[]>;
  valueThresholds: {
    autoCancel: bigint; // Cancel above this value to unknown targets
    humanReview: bigint; // Escalate above this value
  };
  dangerousSelectors: Hex[]; // e.g., approve() to unknown spenders
}

type AlertChannel =
  | { type: "telegram"; botToken: string; chatId: string }
  | { type: "discord"; webhookUrl: string }
  | {
      type: "pagerduty";
      routingKey: string;
      severity: "info" | "warning" | "critical";
    };
```

### 11.12 CancelAuthority

Manages the cancel authority key with KMS-backed storage. Never exposes the raw private key.

```typescript
class CancelAuthority {
  /** Create from KMS-backed key */
  static async fromKMS(config: KMSConfig): Promise<CancelAuthority>;

  /** Create from environment variable (development only) */
  static fromPrivateKey(key: Hex): CancelAuthority;

  /** Cancel a single announcement */
  async cancel(proxyAddress: Address, txId: bigint): Promise<Hash>;

  /** Batch cancel a range */
  async cancelAll(
    proxyAddress: Address,
    fromId: bigint,
    toId: bigint,
  ): Promise<Hash>;

  /** Get the cancel authority address (public, safe to expose) */
  getAddress(): Address;
}

interface KMSConfig {
  provider: "aws-kms" | "hashicorp-vault" | "gcp-kms";
  keyId: string;
  region?: string;
}
```

### 11.13 DelayEngine

Computes appropriate delays for transactions based on configurable risk tier mappings.

```typescript
class DelayEngine {
  constructor(config: DelayConfig);

  /** Compute the delay for a given transaction */
  computeDelay(params: {
    target: Address;
    value: bigint;
    selector?: Hex;
    operation?: string; // e.g., "rebalance", "withdraw", "parameterChange"
  }): DelayResult;

  /** Get all configured risk tiers */
  getTiers(): RiskTier[];

  /** Update tier configuration */
  setTier(tier: RiskTier): void;
}

interface DelayConfig {
  tiers: RiskTier[];
  defaultTier: string; // Tier name for unrecognized operations
}

interface RiskTier {
  name: string; // "routine", "standard", "elevated", "high", "critical"
  delaySeconds: number;
  thresholdUsd?: number;
  operations?: string[];
  selectors?: Hex[];
}

interface DelayResult {
  tier: string;
  delaySeconds: number;
  bypass: boolean; // true if delay is 0 (routine tier)
  reason: string;
}
```

### 11.14 ProxyTypeRegistry

Manage and query proxy type whitelists. Provides default presets for common DeFi integrations.

```typescript
class ProxyTypeRegistry {
  constructor(proxyClient: ProxyClient);

  /** Load a preset whitelist */
  async loadPreset(preset: PresetName): Promise<WhitelistEntry[]>;

  /** Apply a preset to the proxy contract (requires admin) */
  async applyPreset(preset: PresetName): Promise<Hash[]>;

  /** Add a custom whitelist entry */
  async addEntry(
    proxyType: ProxyType,
    target: Address,
    selector?: Hex,
  ): Promise<Hash>;

  /** Check if a call is allowed */
  async isAllowed(
    proxyType: ProxyType,
    target: Address,
    selector: Hex,
  ): Promise<boolean>;

  /** List all entries for a proxy type */
  async listEntries(proxyType: ProxyType): Promise<WhitelistEntry[]>;
}

type PresetName =
  | "defi-trading" // Uniswap Router, swap selectors
  | "vault-participant" // Vault deposit/withdraw, USDC approve
  | "vault-manager" // Full vault management + LP + CCA
  | "governance" // Governor, Timelock, vote/propose/queue/execute
  | "staking"; // Staking contracts, stake/unstake/claim
```

***

## SDK Composability Surface (Normative)

The SDK MUST surface composability information to enable integration with external protocols. See [06-contracts.md](/docs/gotts-vaults/vault/06-contracts.md) Composability Surface for the on-chain requirements.

### Vault Capability Discovery

```typescript
interface VaultCapabilities {
  syncDeposits: boolean;
  syncWithdrawals: boolean;
  asyncDeposits: boolean; // EIP-7540 request/claim
  asyncWithdrawals: boolean; // EIP-7540 request/claim
  sharePoolTrading: boolean; // V4 share pool available
  slippageProtected: boolean; // EIP-5143-style wrappers
}

class VaultClient {
  /** Read the vault's capability bitmap and return structured capabilities */
  async getCapabilities(): Promise<VaultCapabilities>;

  /** Get vault health snapshot for external protocol integration */
  async getHealthSnapshot(): Promise<VaultHealthSnapshot>;
}

interface VaultHealthSnapshot {
  sharePriceVsNav: number; // 1.0 = at NAV
  lastRebalanceTimestamp: number;
  lastHarvestTimestamp: number;
  activeRiskFlags: string[];
  oracleFreshness: number; // seconds since last update
  asyncQueueDepth?: number; // pending async requests
  emergencyMode: "normal" | "slow" | "partial_pause" | "full_pause";
}
```

### Async Request Management

If the vault supports async operations (EIP-7540), the SDK MUST expose:

```typescript
class VaultClient {
  /** Submit an async withdrawal request; returns a receipt NFT token ID */
  async requestRedeem(
    agentId: string,
    shares: string,
  ): Promise<AsyncRequestResult>;

  /** Check claimable amount for an async request */
  async claimableRedeemRequest(requestId: string): Promise<ClaimableInfo>;

  /** Claim completed async request */
  async claimRedeem(requestId: string): Promise<ClaimResult>;
}

interface AsyncRequestResult {
  requestId: string;
  receiptTokenId: string; // ERC-721 receipt NFT
  estimatedClaimTime: number; // Unix timestamp
  queuePosition: number;
  txHash: Hash;
}

interface ClaimableInfo {
  claimable: boolean;
  claimableAmount: string;
  estimatedWaitSeconds: number;
  queuePosition: number;
}
```

> **References**: EIP-7540 async vault standard; Lido WithdrawalQueueERC721 receipt pattern; Pendle SY/PT/YT for yield derivative integration.
