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 2: Get User DeFi Positions by Chain
*
* COMPREHENSIVE DESCRIPTION:
* This tool fetches DeFi positions for a specific wallet address on a single blockchain network.
* It provides detailed information about all DeFi protocol interactions on the specified chain,
* including lending positions, liquidity pools, yield farming, staking, and other DeFi activities.
*
* USE CASES:
* - Chain-specific DeFi analysis
* - Protocol exposure on specific networks
* - Gas optimization planning
* - Chain migration analysis
* - Network-specific risk assessment
* - Layer 2 vs Layer 1 comparison
*
* SUPPORTED CHAINS:
* - eth (Ethereum Mainnet) - Most comprehensive DeFi ecosystem
* - arb (Arbitrum) - Layer 2 scaling solution
* - matic (Polygon) - Low-cost alternative
* - avax (Avalanche) - High-performance blockchain
* - bsc (Binance Smart Chain) - Binance ecosystem
* - base (Base) - Coinbase Layer 2
* - op (Optimism) - Optimistic rollup
* - blast (Blast) - Native yield blockchain
* - linea (Linea) - ConsenSys Layer 2
* - manta (Manta) - Privacy-focused network
*
* RESPONSE FORMAT:
* Returns an array of position objects for the specified chain:
* [
* {
* "protocol": "uniswap-v3",
* "type": "liquidity",
* "pool": "USDC/ETH",
* "value_usd": 5420.50,
* "tokens": [...],
* "rewards": [...],
* "apy": 12.5
* }
* ]
*
* PERFORMANCE:
* - Typical response time: 1-3 seconds (single chain)
* - Faster than cross-chain queries
* - Cached data may be up to 5 minutes old
* - Timeout configured for 180 seconds
*/
export function createGetUserDeFiPositionsByChainTool(client: DataiClient) {
return {
name: "get_defi_by_chain",
description: "Get DeFi positions for a wallet on a specific blockchain network. Provides detailed information about lending, liquidity pools, yield farming, and other DeFi activities on the specified chain.",
parameters: z.object({
wallet: WalletAddressSchema.describe("Ethereum wallet address (42-character hex string starting with 0x) to get DeFi positions 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 Positions by Chain",
category: "Chain Analysis",
tags: ["defi", "chain-specific", "positions", "protocols", "single-chain"]
},
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_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.getUserDeFiPositionsByChain(validatedArgs.wallet, validatedArgs.chain);
const duration = Date.now() - startTime;
const positionCount = Array.isArray(response.data) ? response.data.length : 0;
log.info("DeFi positions by chain fetched successfully", {
executionId,
wallet: validatedArgs.wallet,
chain: validatedArgs.chain,
positionCount,
duration: `${duration}ms`
});
// TEMPORARY: Remove metadata to test if that's causing the validation issue
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 positions 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 chain ${args.chain}. Please try again in a few moments.`,
'TIMEOUT_ERROR'
);
} else if (error instanceof NetworkError) {
throw new DataAIError(
`Network error occurred while fetching ${args.chain} DeFi positions. Please check your connection and try again.`,
'NETWORK_ERROR'
);
} else if (error instanceof APIError) {
if (error.message.includes('404')) {
throw new DataAIError(
`No DeFi positions found for wallet ${args.wallet} on ${args.chain}. The wallet may not be active 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 positions for ${args.chain}: ${error.message}. Please try again or contact support if the issue persists.`,
'UNKNOWN_ERROR'
);
}
}
}
};
}