Staking Operations

Updated

The SDK provides eight staking primitives for protocols like Lido, Ethena, EtherFi, EigenLayer, and others.

ConstantType StringPurpose
PRIMITIVE_STAKING_STAKE"staking_stake"Stake tokens
PRIMITIVE_STAKING_UNSTAKE"staking_unstake"Unstake tokens
PRIMITIVE_STAKING_CLAIM"staking_claim"Claim staking rewards
PRIMITIVE_STAKING_COOLDOWN"staking_cooldown"Initiate cooldown period
PRIMITIVE_STAKING_DELEGATE"staking_delegate"Delegate to an operator
PRIMITIVE_STAKING_UNDELEGATE"staking_undelegate"Undelegate from an operator
PRIMITIVE_STAKING_WRAP"staking_wrap"Wrap staking tokens
PRIMITIVE_STAKING_UNWRAP"staking_unwrap"Unwrap staking tokens

Each primitive has typed params including protocol, asset, amount, and chain.

Stake Tokens

staking-stake.ts
import {
  Chaos,
  WALLET_MODEL,
  extractPrimitives,
  isStakingStakePrimitive,
} 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: 'Stake 10 ETH with Lido',
    },
  ],
  metadata: {
    user_id: 'user-1',
    session_id: 'session-1',
    wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
  },
});
 
const primitives = extractPrimitives(response);
 
for (const primitive of primitives) {
  if (isStakingStakePrimitive(primitive)) {
    // TypeScript knows this is StakingStakePrimitive
    console.log('Stake operation:');
    console.log('  Protocol:', primitive.params.protocol);
    console.log('  Asset:', primitive.params.asset);
    console.log('  Amount:', primitive.params.amount);
    console.log('  Chain:', primitive.params.chain);
  }
}

Unstake Tokens

staking-unstake.ts
import {
  Chaos,
  WALLET_MODEL,
  extractPrimitives,
  isStakingUnstakePrimitive,
} 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: 'Unstake 5 stETH from Lido',
    },
  ],
  metadata: {
    user_id: 'user-1',
    session_id: 'session-1',
    wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
  },
});
 
for (const primitive of extractPrimitives(response)) {
  if (isStakingUnstakePrimitive(primitive)) {
    console.log('Unstake operation:');
    console.log('  Protocol:', primitive.params.protocol);
    console.log('  Asset:', primitive.params.asset);
    console.log('  Amount:', primitive.params.amount);
  }
}

Claim Rewards

staking-claim.ts
import {
  Chaos,
  WALLET_MODEL,
  extractPrimitives,
  isStakingClaimPrimitive,
} 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: 'Claim my staking rewards on EigenLayer',
    },
  ],
  metadata: {
    user_id: 'user-1',
    session_id: 'session-1',
    wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
  },
});
 
for (const primitive of extractPrimitives(response)) {
  if (isStakingClaimPrimitive(primitive)) {
    console.log('Claim rewards:');
    console.log('  Protocol:', primitive.params.protocol);
    console.log('  Asset:', primitive.params.asset);
  }
}

Cooldown Period

Some protocols require initiating a cooldown before unstaking.

staking-cooldown.ts
import {
  Chaos,
  WALLET_MODEL,
  extractPrimitives,
  isStakingCooldownPrimitive,
  isStakingUnstakePrimitive,
} 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: 'Start the cooldown to unstake my sUSDe on Ethena',
    },
  ],
  metadata: {
    user_id: 'user-1',
    session_id: 'session-1',
    wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
  },
});
 
for (const primitive of extractPrimitives(response)) {
  if (isStakingCooldownPrimitive(primitive)) {
    console.log('Cooldown initiated:');
    console.log('  Protocol:', primitive.params.protocol);
    console.log('  Asset:', primitive.params.asset);
  }
 
  if (isStakingUnstakePrimitive(primitive)) {
    console.log('Unstake queued after cooldown:');
    console.log('  Amount:', primitive.params.amount);
  }
}

Delegate and Undelegate

For restaking protocols like EigenLayer that support operator delegation.

staking-delegate.ts
import {
  Chaos,
  WALLET_MODEL,
  extractPrimitives,
  isStakingDelegatePrimitive,
  isStakingUndelegatePrimitive,
} from '@chaoslabs/ai-sdk';
 
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
 
// Delegate
const delegateResponse = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    {
      type: 'message',
      role: 'user',
      content: 'Delegate my restaked ETH on EigenLayer',
    },
  ],
  metadata: {
    user_id: 'user-1',
    session_id: 'session-1',
    wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
  },
});
 
for (const primitive of extractPrimitives(delegateResponse)) {
  if (isStakingDelegatePrimitive(primitive)) {
    console.log('Delegate:');
    console.log('  Protocol:', primitive.params.protocol);
    console.log('  Asset:', primitive.params.asset);
    console.log('  Amount:', primitive.params.amount);
  }
}
 
// Undelegate
const undelegateResponse = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    {
      type: 'message',
      role: 'user',
      content: 'Undelegate my staked assets on EigenLayer',
    },
  ],
  metadata: {
    user_id: 'user-1',
    session_id: 'session-2',
    wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
  },
});
 
for (const primitive of extractPrimitives(undelegateResponse)) {
  if (isStakingUndelegatePrimitive(primitive)) {
    console.log('Undelegate:');
    console.log('  Protocol:', primitive.params.protocol);
    console.log('  Amount:', primitive.params.amount);
  }
}

Wrap and Unwrap

Convert between staking token variants (e.g., stETH to wstETH).

staking-wrap.ts
import {
  Chaos,
  WALLET_MODEL,
  extractPrimitives,
  isStakingWrapPrimitive,
  isStakingUnwrapPrimitive,
} from '@chaoslabs/ai-sdk';
 
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
 
// Wrap stETH -> wstETH
const wrapResponse = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    {
      type: 'message',
      role: 'user',
      content: 'Wrap 5 stETH to wstETH',
    },
  ],
  metadata: {
    user_id: 'user-1',
    session_id: 'session-1',
    wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
  },
});
 
for (const primitive of extractPrimitives(wrapResponse)) {
  if (isStakingWrapPrimitive(primitive)) {
    console.log('Wrap:');
    console.log('  Protocol:', primitive.params.protocol);
    console.log('  Asset:', primitive.params.asset);
    console.log('  Amount:', primitive.params.amount);
  }
}
 
// Unwrap wstETH -> stETH
const unwrapResponse = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    {
      type: 'message',
      role: 'user',
      content: 'Unwrap 3 wstETH to stETH',
    },
  ],
  metadata: {
    user_id: 'user-1',
    session_id: 'session-2',
    wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
  },
});
 
for (const primitive of extractPrimitives(unwrapResponse)) {
  if (isStakingUnwrapPrimitive(primitive)) {
    console.log('Unwrap:');
    console.log('  Protocol:', primitive.params.protocol);
    console.log('  Asset:', primitive.params.asset);
    console.log('  Amount:', primitive.params.amount);
  }
}

Filter All Staking Primitives

Use category helpers to handle all staking operations at once.

staking-filter-all.ts
import {
  Chaos,
  WALLET_MODEL,
  extractPrimitives,
  isStakingPrimitive,
  STAKING_PRIMITIVES,
  extractTransactionBlocks,
  hasRisks,
} 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: 'Stake 10 ETH with Lido and then wrap the stETH to wstETH',
    },
  ],
  metadata: {
    user_id: 'user-1',
    session_id: 'session-1',
    wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
  },
});
 
// Filter to only staking primitives
const allPrimitives = extractPrimitives(response);
const stakingPrimitives = allPrimitives.filter(p => isStakingPrimitive(p.type));
 
console.log(`Found ${stakingPrimitives.length} staking primitives:`);
for (const p of stakingPrimitives) {
  console.log(`  ${p.type} -- ${p.params.protocol} (${p.params.asset ?? 'N/A'})`);
}
 
// Check risks before executing
if (hasRisks(response)) {
  const blocks = extractTransactionBlocks(response);
  for (const block of blocks) {
    console.log(`Risk level: ${block.risks.level}`);
    if (block.risks.warnings) {
      for (const w of block.risks.warnings) {
        console.log(`  Warning: ${w.title} -- ${w.message}`);
      }
    }
  }
}
 
// Available staking primitive types
console.log('\nAll staking primitive types:', STAKING_PRIMITIVES);
// => ['staking_stake', 'staking_unstake', 'staking_claim',
//     'staking_cooldown', 'staking_delegate', 'staking_undelegate',
//     'staking_wrap', 'staking_unwrap']
[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop
Was this helpful?