import { z } from 'zod';
import { DataiClient } from '../utils/api-client.js';
import { WalletAddressSchema, ChainSchema } from '../utils/validation.js';
import { DataAIError, ValidationError, APIError, NetworkError, TimeoutError } from '../utils/error-handler.js';
/**
* Tool 8: Get Wallet Token Balances by Chain
*
* COMPREHENSIVE DESCRIPTION:
* This tool fetches token balances for a specific wallet address on a single blockchain network.
* It provides detailed information about all token holdings (ERC-20, native tokens, etc.) on the specified chain,
* including token amounts, USD values, and token metadata. Perfect for token portfolio analysis and asset tracking.
*
* USE CASES:
* - Token portfolio analysis on specific chains
* - Asset allocation tracking
* - Token diversification assessment
* - Chain-specific token exposure
* - Token balance monitoring
* - Asset migration planning
*
* TOKEN TYPES SUPPORTED:
* - Native tokens (ETH, MATIC, AVAX, BNB, etc.)
* - ERC-20 tokens (USDC, USDT, DAI, WETH, etc.)
* - Governance tokens (UNI, AAVE, COMP, etc.)
* - Stablecoins (USDC, USDT, DAI, FRAX, etc.)
* - Wrapped tokens (WETH, WBTC, etc.)
* - Protocol tokens (specific to each chain)
*
* RESPONSE FORMAT:
* Returns an array of token balance objects:
* [
* {
* "token_address": "0xA0b86a33E6...",
* "token_symbol": "USDC",
* "token_name": "USD Coin",
* "balance": "1542.50",
* "balance_usd": 1542.50,
* "decimals": 6,
* "price_usd": 1.00
* }
* ]
*
* PERFORMANCE:
* - Typical response time: 1-3 seconds (single chain)
* - Fast token balance retrieval
* - Real-time price data
* - Optimized for token analysis
*/
export function createGetWalletBalancesByChainTool(client: DataiClient) {
return {
name: "get_wallet_balances_by_chain",
description: "Get token balances for a wallet on a specific blockchain network. Provides detailed information about all token holdings including amounts, USD values, and token metadata for portfolio analysis.",
parameters: z.object({
wallet: WalletAddressSchema.describe("Ethereum wallet address (42-character hex string starting with 0x) to get token balances for"),
chain: ChainSchema.describe("Blockchain network to query. Supported: 'eth' (Ethereum), 'arb' (Arbitrum), 'matic' (Polygon), 'avax' (Avalanche), 'bsc' (BSC), 'base' (Base), 'op' (Optimism)")
}),
annotations: {
readOnlyHint: true,
destructiveHint: false,
openWorldHint: true,
idempotentHint: true,
streamingHint: false,
title: "Token Balances by Chain",
category: "Token Analysis",
tags: ["tokens", "balances", "portfolio", "assets", "chain-specific", "erc20"]
},
execute: async (args: { wallet: string; chain: string }, context: { log: any }) => {
const { log } = context;
const startTime = Date.now();
const executionId = crypto.randomUUID().slice(0, 8);
log.info("Starting get_wallet_balances_by_chain", {
executionId,
wallet: args.wallet,
chain: args.chain
});
try {
// Validate parameters
const validatedArgs = {
wallet: WalletAddressSchema.parse(args.wallet),
chain: ChainSchema.parse(args.chain)
};
// Make API request
const response = await client.getWalletBalancesByChain(validatedArgs.wallet, validatedArgs.chain);
const duration = Date.now() - startTime;
const tokenCount = Array.isArray(response.data) ? response.data.length : 0;
log.info("Wallet balances by chain fetched successfully", {
executionId,
wallet: validatedArgs.wallet,
chain: validatedArgs.chain,
tokenCount,
duration: `${duration}ms`
});
return {
content: [{
type: "text" as const,
text: JSON.stringify(response.data, null, 2)
}]
};
} catch (error: any) {
const duration = Date.now() - startTime;
log.error("Failed to fetch wallet token balances by chain", {
executionId,
wallet: args.wallet,
chain: args.chain,
duration: `${duration}ms`,
error: error.message,
errorType: error.constructor.name,
errorCode: error.code || 'UNKNOWN',
success: false
});
// Transform error for user-friendly response
if (error instanceof ValidationError) {
if (error.message.includes('wallet')) {
throw new DataAIError(
`Invalid wallet address: ${args.wallet}. Please provide a valid Ethereum address (42 characters, starting with 0x).`,
'VALIDATION_ERROR'
);
} else if (error.message.includes('chain')) {
throw new DataAIError(
`Invalid chain: ${args.chain}. Supported chains: eth, arb, matic, avax, bsc, base, op, blast, linea, manta.`,
'VALIDATION_ERROR'
);
} else {
throw new DataAIError(`Invalid parameters: ${error.message}`, 'VALIDATION_ERROR');
}
} else if (error instanceof TimeoutError) {
throw new DataAIError(
`Request timed out after ${duration}ms for ${args.chain} token balances. Please try again in a few moments.`,
'TIMEOUT_ERROR'
);
} else if (error instanceof NetworkError) {
throw new DataAIError(
`Network error occurred while fetching ${args.chain} token balances. Please check your connection and try again.`,
'NETWORK_ERROR'
);
} else if (error instanceof APIError) {
if (error.message.includes('404')) {
throw new DataAIError(
`No token balances found for wallet ${args.wallet} on ${args.chain}. The wallet may not have any tokens on this chain.`,
'NOT_FOUND'
);
} else if (error.message.includes('429')) {
throw new DataAIError(
'Rate limit exceeded. Please wait a moment before making another request.',
'RATE_LIMIT_EXCEEDED'
);
} else {
throw new DataAIError(`API error: ${error.message}`, 'API_ERROR');
}
} else {
throw new DataAIError(
`Failed to fetch token balances for ${args.chain}: ${error.message}. Please try again or contact support if the issue persists.`,
'UNKNOWN_ERROR'
);
}
}
}
};
}