| name | eth-agent |
| description | Expert knowledge for using the eth-agent library - the simplest, safest way for AI agents to send stablecoins on Ethereum. Use when writing code that interacts with Ethereum, sends tokens, or builds AI agent payment systems. |
| argument-hint | ["task description"] |
eth-agent Library Expert
You are an expert in the eth-agent library - a TypeScript library that provides the simplest, safest way for AI agents to interact with Ethereum and send stablecoins.
Core Philosophy
- Simplicity: Send USDC in one line, not 15+
- Safety First: Built-in spending limits, human approval, address policies
- AI-Centric: Structured errors with suggestions, predictable APIs
- Human-in-the-Loop: Easy integration with approval workflows
Installation
npm install @lambdaclass/eth-agent
Quick Start
import { AgentWallet } from '@lambdaclass/eth-agent';
const wallet = AgentWallet.create({
privateKey: process.env.ETH_PRIVATE_KEY,
rpcUrl: 'https://eth.llamarpc.com',
});
await wallet.sendUSDC({ to: 'alice.eth', amount: '100' });
await wallet.sendUSDT({ to: 'bob.eth', amount: '50.25' });
await wallet.send({ to: 'alice.eth', amount: '0.1 ETH' });
Stablecoins
The library has first-class support for major stablecoins across chains:
import { USDC, USDT, USDS, DAI, PYUSD, FRAX } from '@lambdaclass/eth-agent';
await wallet.sendUSDC({ to: 'alice.eth', amount: '100' });
await wallet.sendUSDT({ to: 'bob.eth', amount: '50.25' });
await wallet.sendStablecoin({ token: DAI, to: 'carol.eth', amount: '1000' });
const balance = await wallet.getStablecoinBalance(USDC);
const allBalances = await wallet.getStablecoinBalances();
Supported Chains for Stablecoins
USDC, USDT, DAI are available on: Ethereum, Arbitrum, Optimism, Base, Polygon, Avalanche
Safety Features
Spending Limits
const wallet = AgentWallet.create({
privateKey: KEY,
rpcUrl: URL,
limits: {
perTransaction: '100',
perHour: '500',
perDay: '2000',
emergencyStopBelow: '10',
},
});
const limits = await wallet.getLimits();
console.log(limits.daily.remaining);
Human Approval
const wallet = AgentWallet.create({
privateKey: KEY,
rpcUrl: URL,
approvalConfig: {
requireApprovalWhen: {
amountExceeds: '50',
recipientIsNew: true,
recipientNotInTrusted: true
},
trustedAddresses: ['0x...', 'alice.eth'],
},
onApprovalRequired: async (request) => {
console.log(`Approval needed: ${request.summary}`);
return await askHumanForApproval(request);
},
});
Address Policies
const wallet = AgentWallet.create({
privateKey: KEY,
rpcUrl: URL,
addressPolicy: {
mode: 'allowlist',
addresses: ['0x...', 'alice.eth', 'bob.eth'],
},
});
Error Handling
Safe Methods (Result Type)
All methods have safe* variants that return Result types instead of throwing:
import { isOk, isErr, matchResult } from '@lambdaclass/eth-agent';
const result = await wallet.safeSendUSDC({ to: 'alice.eth', amount: '100' });
if (isOk(result)) {
console.log(`Success! TX: ${result.value.hash}`);
} else {
console.log(`Error: ${result.error.code}`);
console.log(`Suggestion: ${result.error.suggestion}`);
}
Pattern Matching
const message = matchResult(result)
.ok(r => `Sent! TX: ${r.hash}`)
.errWith({ code: 'INSUFFICIENT_FUNDS' }, e => `Need more: ${e.details.shortage}`)
.errWith({ code: 'DAILY_LIMIT_EXCEEDED' }, () => 'Wait until tomorrow')
.errWith({ code: 'APPROVAL_REQUIRED' }, () => 'Human approval needed')
.err(e => e.suggestion)
.run();
Structured Errors
All errors have:
code: Machine-readable (e.g., DAILY_LIMIT_EXCEEDED)
message: Human-readable description
suggestion: Recovery action
retryable: Boolean
retryAfter: Milliseconds to wait (if applicable)
Transaction Preview
Preview transactions before sending:
const preview = await wallet.preview({
to: 'alice.eth',
amount: '0.5 ETH',
});
console.log(preview.canExecute);
console.log(preview.costs.total.eth);
console.log(preview.costs.gas.eth);
console.log(preview.blockers);
console.log(preview.warnings);
Smart Accounts (Gasless Transactions)
For gasless and batch operations using ERC-4337:
import { SmartAgentWallet, createRemotePaymaster } from '@lambdaclass/eth-agent';
const smartWallet = SmartAgentWallet.create({
privateKey: KEY,
rpcUrl: URL,
bundlerUrl: 'https://bundler.example.com',
paymaster: createRemotePaymaster({ url: PAYMASTER_URL }),
});
await smartWallet.sendUSDCGasless({ to: 'alice.eth', amount: '100' });
await smartWallet.sendStablecoinBatch({
token: USDC,
transfers: [
{ to: 'alice.eth', amount: '50' },
{ to: 'bob.eth', amount: '30' },
{ to: 'carol.eth', amount: '20' },
],
});
Payment Watching
Monitor incoming payments:
import { USDC, USDT } from '@lambdaclass/eth-agent';
const watcher = wallet.onStablecoinReceived((payment) => {
console.log(`Received ${payment.formattedAmount} ${payment.token.symbol}`);
}, { tokens: [USDC, USDT] });
watcher.stop();
const payment = await wallet.waitForPayment({
token: USDC,
minAmount: '100',
timeout: 60000,
});
Cross-Chain Bridging
Bridge stablecoins between chains using the unified BridgeRouter:
import { USDC } from '@lambdaclass/eth-agent';
const result = await wallet.bridge({
token: USDC,
amount: '100',
destinationChainId: 42161,
});
console.log(result.trackingId);
console.log(result.summary);
Route Preferences
Control how the router selects bridges:
const fast = await wallet.bridge({
token: USDC,
amount: '500',
destinationChainId: 8453,
preference: {
priority: 'speed',
maxSlippageBps: 50,
},
});
const viaCCTP = await wallet.bridge({
token: USDC,
amount: '1000',
destinationChainId: 10,
protocol: 'CCTP',
});
Compare Routes Before Bridging
const routes = await wallet.compareBridgeRoutes({
token: USDC,
amount: '1000',
destinationChainId: 8453,
});
console.log(routes.recommendation.reason);
for (const quote of routes.quotes) {
console.log(`${quote.protocol}: ${quote.fee.totalUSD} USD fee`);
}
Preview Bridge with Validation
const preview = await wallet.previewBridgeWithRouter({
token: USDC,
amount: '1000',
destinationChainId: 42161,
});
if (preview.canBridge) {
console.log(`Ready to bridge. Fee: $${preview.quote?.fee.totalUSD}`);
console.log(`Needs approval: ${preview.needsApproval}`);
} else {
console.log('Cannot bridge:', preview.blockers.join(', '));
}
Track Bridge Status
const result = await wallet.bridge({ ... });
const status = await wallet.getBridgeStatusByTrackingId(result.trackingId);
console.log(`Progress: ${status.progress}%`);
console.log(`Message: ${status.message}`);
const attestation = await wallet.waitForBridgeByTrackingId(result.trackingId);
console.log('Bridge completed!');
Safe Bridge (Result Type)
const result = await wallet.safeBridge({
token: USDC,
amount: '100',
destinationChainId: 42161,
});
if (isOk(result)) {
console.log(`Success! Tracking: ${result.value.trackingId}`);
} else {
console.log(`Error: ${result.error.code}`);
console.log(`Suggestion: ${result.error.suggestion}`);
}
Supported Bridge Protocols
| Protocol | Tokens | Speed | Fees | Notes |
|---|
| CCTP (Circle) | USDC | 10-20 min | $0 | No slippage, 1:1 burn/mint |
| Stargate | USDC, USDT | 5-15 min | ~0.06% | Has slippage |
| Across | USDC, USDT | 2-5 min | Variable | Instant delivery |
Legacy USDC-Only Method
For direct CCTP bridging without route selection:
const result = await wallet.bridgeUSDC({
amount: '100',
destinationChainId: 42161,
});
const status = await wallet.getBridgeStatus(result.messageHash);
AI Framework Integration
Anthropic (Claude)
import { AgentWallet } from '@lambdaclass/eth-agent';
import { anthropicTools } from '@lambdaclass/eth-agent/integrations';
import Anthropic from '@anthropic-ai/sdk';
const wallet = AgentWallet.create({ privateKey: KEY, rpcUrl: URL });
const tools = anthropicTools(wallet);
const response = await client.messages.create({
model: 'claude-sonnet-4-20250514',
tools: tools.definitions,
messages: [{ role: 'user', content: 'Send 10 USDC to alice.eth' }],
});
for (const block of response.content) {
if (block.type === 'tool_use') {
const result = await tools.execute(block.name, block.input);
}
}
OpenAI
import { openaiTools } from '@lambdaclass/eth-agent/integrations';
const tools = openaiTools(wallet);
LangChain
import { langchainTools } from '@lambdaclass/eth-agent/integrations';
const tools = langchainTools(wallet);
Key Imports
import { AgentWallet, SmartAgentWallet } from '@lambdaclass/eth-agent';
import { USDC, USDT, USDS, DAI, PYUSD, FRAX, STABLECOINS } from '@lambdaclass/eth-agent';
import { ok, err, isOk, isErr, matchResult, unwrap } from '@lambdaclass/eth-agent';
import { ETH, GWEI, WEI, parseUnits, formatUnits } from '@lambdaclass/eth-agent';
import { anthropicTools, openaiTools, langchainTools } from '@lambdaclass/eth-agent/integrations';
import { createRemotePaymaster, createVerifyingPaymaster } from '@lambdaclass/eth-agent';
import { BridgeRouter, type RoutePreference } from '@lambdaclass/eth-agent';
Common Patterns
1. Simple Payment Agent
const wallet = AgentWallet.create({
privateKey: process.env.ETH_PRIVATE_KEY,
rpcUrl: process.env.RPC_URL,
limits: { perTransaction: '100', perDay: '1000' },
});
async function payUser(recipient: string, amount: string) {
const result = await wallet.safeSendUSDC({ to: recipient, amount });
if (isOk(result)) {
return { success: true, txHash: result.value.hash };
}
return { success: false, error: result.error.suggestion };
}
2. Approval-Gated Payments
const wallet = AgentWallet.create({
privateKey: KEY,
rpcUrl: URL,
approvalConfig: {
requireApprovalWhen: { amountExceeds: '50' },
},
onApprovalRequired: async (req) => {
return await slackApprovalFlow(req.summary);
},
});
3. Multi-Recipient Batch
const smartWallet = SmartAgentWallet.create({ ... });
await smartWallet.sendStablecoinBatch({
token: USDC,
transfers: recipients.map(r => ({ to: r.address, amount: r.amount })),
});
4. Cross-Chain Payment with Bridge
async function sendCrossChain(
recipient: string,
amount: string,
destChainId: number
) {
const preview = await wallet.previewBridgeWithRouter({
token: USDC,
amount,
destinationChainId: destChainId,
recipient,
});
if (!preview.canBridge) {
return { success: false, error: preview.blockers.join(', ') };
}
const result = await wallet.safeBridge({
token: USDC,
amount,
destinationChainId: destChainId,
recipient,
});
if (isOk(result)) {
return {
success: true,
trackingId: result.value.trackingId,
summary: result.value.summary,
};
}
return { success: false, error: result.error.suggestion };
}
Task: $ARGUMENTS
Based on the above knowledge, help with the requested task.