Lending Operations

Updated

This recipe demonstrates a complete lending workflow: depositing collateral, borrowing an asset, and repaying a loan. Each step uses the appropriate primitive constant and type guard for safe extraction.

[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop

Full Example

lending.ts
import {
  Chaos,
  WALLET_MODEL,
  PRIMITIVE_LENDING_DEPOSIT,
  PRIMITIVE_LENDING_BORROW,
  PRIMITIVE_LENDING_REPAY,
  findTransactionsByPrimitive,
  extractPrimitives,
  isLendingDepositPrimitive,
  isLendingBorrowPrimitive,
  isLendingRepayPrimitive,
  hasRisks,
  getHighestRiskLevel,
  getAllWarnings,
} from '@chaoslabs/ai-sdk';
 
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
 
const walletMeta = {
  user_id: 'user-123',
  session_id: 'session-lending',
  wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
};
 
// ─── Step 1: Deposit Collateral ─────────────────────────────────────────────────
 
const depositResponse = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    { type: 'message', role: 'user', content: 'Deposit 10 ETH as collateral on Aave' },
  ],
  metadata: walletMeta,
});
 
// Find action blocks containing the deposit primitive
const depositBlocks = findTransactionsByPrimitive(depositResponse, PRIMITIVE_LENDING_DEPOSIT);
console.log(`Found ${depositBlocks.length} deposit action block(s)`);
 
// Extract and narrow the deposit primitive
const depositPrimitives = extractPrimitives(depositResponse).filter(isLendingDepositPrimitive);
for (const dep of depositPrimitives) {
  console.log('Deposit:', {
    type: dep.type,        // 'lending_deposit'
    params: dep.params,    // LendingDepositParams (token, amount, protocol, etc.)
    display: dep.display,  // PrimitiveDisplay (action_verb, summary, etc.)
  });
}
 
// ─── Step 2: Borrow ─────────────────────────────────────────────────────────────
 
const borrowResponse = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    { type: 'message', role: 'user', content: 'Borrow 5000 USDC against my collateral on Aave' },
  ],
  metadata: walletMeta,
});
 
const borrowBlocks = findTransactionsByPrimitive(borrowResponse, PRIMITIVE_LENDING_BORROW);
const borrowPrimitives = extractPrimitives(borrowResponse).filter(isLendingBorrowPrimitive);
 
for (const borrow of borrowPrimitives) {
  console.log('Borrow:', borrow.params);
}
 
// Check risk levels on the borrow
if (hasRisks(borrowResponse)) {
  console.warn('Borrow risk:', getHighestRiskLevel(borrowResponse));
  console.warn('Warnings:', getAllWarnings(borrowResponse).map((w) => w.message));
}
 
// ─── Step 3: Repay ──────────────────────────────────────────────────────────────
 
const repayResponse = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    { type: 'message', role: 'user', content: 'Repay 2500 USDC on Aave' },
  ],
  metadata: walletMeta,
});
 
const repayBlocks = findTransactionsByPrimitive(repayResponse, PRIMITIVE_LENDING_REPAY);
const repayPrimitives = extractPrimitives(repayResponse).filter(isLendingRepayPrimitive);
 
for (const repay of repayPrimitives) {
  console.log('Repay:', repay.params);
}
 
// ─── Summary ────────────────────────────────────────────────────────────────────
 
console.log('Lending workflow complete:', {
  deposits: depositBlocks.length,
  borrows: borrowBlocks.length,
  repays: repayBlocks.length,
});

Finding Transactions by Primitive

findTransactionsByPrimitive filters action blocks to only those containing a given primitive type. This is useful when a response includes multiple action blocks (e.g., an approve + deposit).

find-by-primitive.ts
import {
  findTransactionsByPrimitive,
  PRIMITIVE_LENDING_DEPOSIT,
} from '@chaoslabs/ai-sdk';
 
// Returns ActionBlock[] where at least one primitive has type 'lending_deposit'
const blocks = findTransactionsByPrimitive(response, PRIMITIVE_LENDING_DEPOSIT);
 
for (const block of blocks) {
  console.log('Notes:', block.notes);
  console.log('Primitives:', block.primitives?.map((p) => p.type));
  console.log('Transactions:', block.transactions?.length);
}

Type-Safe Primitive Extraction

Each primitive type guard narrows the Primitive union to a specific type with typed params.

type-guards.ts
import {
  extractPrimitives,
  isLendingDepositPrimitive,
  isLendingBorrowPrimitive,
  isLendingRepayPrimitive,
  isLendingWithdrawPrimitive,
  isLendingClaimRewardsPrimitive,
} from '@chaoslabs/ai-sdk';
 
const primitives = extractPrimitives(response);
 
for (const p of primitives) {
  if (isLendingDepositPrimitive(p)) {
    // p is LendingDepositPrimitive, p.params is LendingDepositParams
    console.log('Deposit:', p.params);
  } else if (isLendingBorrowPrimitive(p)) {
    // p is LendingBorrowPrimitive, p.params is LendingBorrowParams
    console.log('Borrow:', p.params);
  } else if (isLendingRepayPrimitive(p)) {
    // p is LendingRepayPrimitive, p.params is LendingRepayParams
    console.log('Repay:', p.params);
  } else if (isLendingWithdrawPrimitive(p)) {
    // p is LendingWithdrawPrimitive, p.params is LendingWithdrawParams
    console.log('Withdraw:', p.params);
  } else if (isLendingClaimRewardsPrimitive(p)) {
    // p is LendingClaimRewardsPrimitive, p.params is LendingClaimRewardsParams
    console.log('Claim rewards:', p.params);
  }
}
[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop
[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop
Was this helpful?