Wallet Configuration

Updated

When using WALLET_MODEL, the Chaos AI platform reads your on-chain portfolio data to provide personalized analysis and transaction recommendations. This guide covers how to configure wallets, work with multiple chains, and use context overrides for deterministic testing.

WalletInfo basics

A wallet is defined by the WalletInfo interface:

types.ts
interface WalletInfo {
  address: string; // Wallet address (e.g., '0x...')
  chain: string;   // Blockchain identifier (e.g., 'ethereum', 'arbitrum')
}

Pass wallets in the metadata.wallets array when creating a request:

wallet-basic.ts
import { Chaos, WALLET_MODEL } from '@chaoslabs/ai-sdk';
 
const chaos = new Chaos({
  apiKey: process.env.CHAOS_API_KEY!,
});
 
const response = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    { type: 'message', role: 'user', content: 'What is my portfolio value?' },
  ],
  metadata: {
    user_id: 'user-123',
    session_id: 'session-abc',
    wallets: [
      { address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', chain: 'ethereum' },
    ],
  },
});

Multi-chain wallets

The wallets array accepts multiple entries. This lets you query positions across different chains in a single request:

wallet-multichain.ts
import { Chaos, WALLET_MODEL } from '@chaoslabs/ai-sdk';
 
const chaos = new Chaos({
  apiKey: process.env.CHAOS_API_KEY!,
});
 
const response = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    { type: 'message', role: 'user', content: 'Show all my DeFi positions across chains' },
  ],
  metadata: {
    user_id: 'user-123',
    session_id: 'session-abc',
    wallets: [
      { address: '0xYourWallet', chain: 'ethereum' },
      { address: '0xYourWallet', chain: 'arbitrum' },
      { address: '0xYourWallet', chain: 'base' },
      { address: '0xYourWallet', chain: 'optimism' },
    ],
  },
});
[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop

You can also use different addresses per chain:

wallet-different-addresses.ts
const response = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    { type: 'message', role: 'user', content: 'Compare my positions across wallets' },
  ],
  metadata: {
    user_id: 'user-123',
    session_id: 'session-abc',
    wallets: [
      { address: '0xWalletA', chain: 'ethereum' },
      { address: '0xWalletB', chain: 'arbitrum' },
      { address: '0xWalletC', chain: 'base' },
    ],
  },
});

RequestMetadata reference

The metadata field on every request has this shape:

types.ts
interface RequestMetadata {
  user_id: string;                              // Your user identifier
  session_id: string;                           // Session identifier for conversation continuity
  wallets?: WalletInfo[];                       // Array of wallets to query
  wallet_context_override?: WalletContextOverride; // Override wallet data (testing)
}
FieldRequiredDescription
user_idYesIdentifies the user making the request
session_idYesGroups messages into a conversation. Use the same ID for follow-up questions
walletsNoArray of WalletInfo objects. Required for WALLET_MODEL to fetch on-chain data
wallet_context_overrideNoReplaces the live on-chain lookup with static data. Useful for testing

WalletContextOverride for deterministic testing

When building and testing your integration, you may not want to depend on live on-chain data that changes constantly. WalletContextOverride lets you provide a fixed wallet state so the AI always sees the same portfolio.

types.ts
interface WalletContextOverride {
  wallet_address: string;            // Wallet address being simulated
  balances: BalanceOverride[];       // Token balances
  protocol_positions?: ProtocolPositionOverride[]; // DeFi positions
  prices?: Record<string, number>;  // Token prices by symbol
}
 
interface BalanceOverride {
  symbol: string;     // Token symbol (e.g., 'ETH', 'USDC')
  amount: number;     // Token amount held
  chain: string;      // Blockchain (e.g., 'ethereum')
  price?: number;     // USD price per unit
  value_usd?: number; // Total USD value (fallback)
}

Basic override example

Here is a minimal override that sets a fixed wallet with ETH and USDC balances:

wallet-override-basic.ts
import { Chaos, WALLET_MODEL } from '@chaoslabs/ai-sdk';
 
const chaos = new Chaos({
  apiKey: process.env.CHAOS_API_KEY!,
});
 
const response = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    { type: 'message', role: 'user', content: 'What is my portfolio value?' },
  ],
  metadata: {
    user_id: 'test-user',
    session_id: 'test-session',
    wallets: [{ address: '0xTestWallet', chain: 'ethereum' }],
    wallet_context_override: {
      wallet_address: '0xTestWallet',
      balances: [
        { symbol: 'ETH', amount: 10, chain: 'ethereum', price: 3500 },
        { symbol: 'USDC', amount: 50000, chain: 'ethereum', price: 1 },
        { symbol: 'WBTC', amount: 0.5, chain: 'ethereum', price: 95000 },
      ],
      prices: {
        ETH: 3500,
        USDC: 1,
        WBTC: 95000,
      },
    },
  },
});
[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop

Override with protocol positions

You can also include DeFi protocol positions (lending, staking, LP) in the override:

wallet-override-positions.ts
import { Chaos, WALLET_MODEL } from '@chaoslabs/ai-sdk';
 
const chaos = new Chaos({
  apiKey: process.env.CHAOS_API_KEY!,
});
 
const response = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    { type: 'message', role: 'user', content: 'What are my lending positions?' },
  ],
  metadata: {
    user_id: 'test-user',
    session_id: 'test-session',
    wallets: [{ address: '0xTestWallet', chain: 'ethereum' }],
    wallet_context_override: {
      wallet_address: '0xTestWallet',
      balances: [
        { symbol: 'ETH', amount: 5, chain: 'ethereum', price: 3500 },
        { symbol: 'USDC', amount: 10000, chain: 'ethereum', price: 1 },
      ],
      protocol_positions: [
        {
          id: 'aave-v3',
          name: 'Aave V3',
          chain: 'ethereum',
          portfolio_items: [
            {
              name: 'Supply',
              assets: [
                {
                  symbol: 'WETH',
                  amount: 3.0,
                  price: 3500,
                },
              ],
            },
            {
              name: 'Borrow',
              assets: [
                {
                  symbol: 'USDC',
                  amount: 5000,
                  price: 1,
                },
              ],
            },
          ],
        },
      ],
      prices: {
        ETH: 3500,
        WETH: 3500,
        USDC: 1,
      },
    },
  },
});

Using overrides with the Conversation class

The Conversation class accepts walletContextOverride in its constructor options:

wallet-override-conversation.ts
import { Chaos, Conversation } from '@chaoslabs/ai-sdk';
 
const chaos = new Chaos({
  apiKey: process.env.CHAOS_API_KEY!,
});
 
const conversation = new Conversation(chaos, {
  userId: 'test-user',
  wallets: [{ address: '0xTestWallet', chain: 'ethereum' }],
  walletContextOverride: {
    wallet_address: '0xTestWallet',
    balances: [
      { symbol: 'ETH', amount: 10, chain: 'ethereum', price: 3500 },
      { symbol: 'USDC', amount: 25000, chain: 'ethereum', price: 1 },
    ],
    prices: { ETH: 3500, USDC: 1 },
  },
});
 
// All messages in this conversation use the overridden wallet context
const r1 = await conversation.send('What is my portfolio value?');
const r2 = await conversation.send('Should I deposit more ETH into Aave?');

Next steps

Was this helpful?