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 5: Get User DeFi Protocol Balances by Chain
*
* COMPREHENSIVE DESCRIPTION:
* This tool fetches DeFi protocol balances for a specific wallet address on a single blockchain network.
* It provides aggregated balance information grouped by protocol, showing total value locked (TVL) per protocol
* on the specified chain. Perfect for protocol diversification analysis and risk assessment.
*
* USE CASES:
* - Protocol diversification analysis on specific chains
* - Risk concentration assessment
* - Protocol performance comparison
* - Chain-specific protocol exposure
* - Rebalancing strategy planning
* - Protocol yield comparison
*
* RESPONSE FORMAT:
* Returns protocol balance summaries for the specified chain:
* [
* {
* "protocol": "uniswap-v3",
* "total_value_usd": 15420.50,
* "position_count": 3,
* "types": ["liquidity", "farming"],
* "apy_range": [8.5, 15.2]
* }
* ]
*
* PERFORMANCE:
* - Typical response time: 1-2 seconds (aggregated data)
* - Faster than detailed position queries
* - Optimized for balance overview
*/
export function createGetUserDeFiProtocolBalancesByChainTool(client: DataiClient) {
return {
name: "get_defi_balances_by_chain",
description: "Get DeFi protocol balances for a wallet on a specific blockchain network. Provides aggregated balance information grouped by protocol for diversification analysis and risk assessment.",
parameters: z.object({
wallet: WalletAddressSchema.describe("Ethereum wallet address (42-character hex string starting with 0x) to get DeFi protocol 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: "DeFi Protocol Balances by Chain",
category: "Balance Analysis",
tags: ["defi", "protocol-balances", "aggregated", "diversification", "risk-assessment"]
},
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_defi_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.getUserDeFiProtocolBalancesByChain(validatedArgs.wallet, validatedArgs.chain);
const duration = Date.now() - startTime;
const protocolCount = Array.isArray(response.data) ? response.data.length : 0;
log.info("DeFi protocol balances by chain fetched successfully", {
executionId,
wallet: validatedArgs.wallet,
chain: validatedArgs.chain,
protocolCount,
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 DeFi protocol 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} protocol 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} protocol balances. Please check your connection and try again.`,
'NETWORK_ERROR'
);
} else if (error instanceof APIError) {
if (error.message.includes('404')) {
throw new DataAIError(
`No DeFi protocol balances found for wallet ${args.wallet} on ${args.chain}. The wallet may not have any DeFi positions 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 DeFi protocol balances for ${args.chain}: ${error.message}. Please try again or contact support if the issue persists.`,
'UNKNOWN_ERROR'
);
}
}
}
};
}