Skip to main content
Glama
clumsynonono

Aave Liquidation MCP Server

by clumsynonono

batch_check_addresses

Check multiple Ethereum addresses simultaneously for Aave V3 liquidation risks by analyzing health factors and positions.

Instructions

Batch check multiple Ethereum addresses for liquidation opportunities. Returns a summary of all addresses with their health status.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
addressesYesArray of Ethereum addresses to check (max 20 addresses)

Implementation Reference

  • Main handler for 'batch_check_addresses' tool execution. Validates input addresses, calls batchAnalyzeLiquidation on AaveClient, processes results into summary statistics, and returns formatted JSON response.
    case 'batch_check_addresses': {
      const addresses = args?.addresses as string[];
      if (!Array.isArray(addresses) || addresses.length === 0) {
        throw new McpError(
          ErrorCode.InvalidParams,
          'addresses parameter is required and must be a non-empty array'
        );
      }
    
      if (addresses.length > 20) {
        throw new McpError(
          ErrorCode.InvalidParams,
          'Maximum 20 addresses allowed per batch request'
        );
      }
    
      // Validate all addresses first
      const invalidAddresses = addresses.filter(
        (addr) => typeof addr !== 'string' || !aaveClient.isValidAddress(addr)
      );
      if (invalidAddresses.length > 0) {
        throw new McpError(
          ErrorCode.InvalidParams,
          `Invalid Ethereum addresses: ${invalidAddresses.join(', ')}`
        );
      }
    
      const results = await aaveClient.batchAnalyzeLiquidation(addresses);
    
      // Calculate summary statistics
      let liquidatable = 0;
      let atRisk = 0;
      let healthy = 0;
      let failed = 0;
    
      const formattedResults = results.map((r) => {
        // Count statistics
        if (r.error) {
          failed++;
        } else if (r.opportunity?.riskLevel === 'HIGH') {
          liquidatable++;
        } else if (r.opportunity) {
          atRisk++;
        } else {
          healthy++;
        }
    
        return {
          address: r.address,
          status: r.error
            ? 'ERROR'
            : r.opportunity
            ? r.opportunity.riskLevel === 'HIGH'
              ? 'LIQUIDATABLE'
              : 'AT_RISK'
            : 'HEALTHY',
          healthFactor: r.opportunity?.healthFactor || 'N/A',
          totalDebtUSD: r.opportunity?.totalDebtUSD || '0',
          riskLevel: r.opportunity?.riskLevel || 'NONE',
          error: r.error,
        };
      });
    
      const summary = {
        totalChecked: addresses.length,
        successful: addresses.length - failed,
        failed,
        liquidatable,
        atRisk,
        healthy,
        results: formattedResults,
      };
    
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify(summary, null, 2),
          },
        ],
      };
    }
  • Input schema definition for the batch_check_addresses tool, specifying an array of Ethereum addresses (max 20).
    {
      name: 'batch_check_addresses',
      description:
        'Batch check multiple Ethereum addresses for liquidation opportunities. Returns a summary of all addresses with their health status.',
      inputSchema: {
        type: 'object',
        properties: {
          addresses: {
            type: 'array',
            items: {
              type: 'string',
            },
            description: 'Array of Ethereum addresses to check (max 20 addresses)',
          },
        },
        required: ['addresses'],
      },
    },
  • src/index.ts:48-164 (registration)
    Registration of all tools including batch_check_addresses via the ListToolsRequestHandler.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: 'get_user_health',
            description:
              'Get health factor and account data for a specific Ethereum address on Aave V3. Returns collateral, debt, and liquidation status.',
            inputSchema: {
              type: 'object',
              properties: {
                address: {
                  type: 'string',
                  description: 'Ethereum address to check (must be a valid address)',
                },
              },
              required: ['address'],
            },
          },
          {
            name: 'analyze_liquidation',
            description:
              'Analyze a user position for liquidation opportunity. Returns detailed information including collateral assets, debt assets, risk level, and potential profit.',
            inputSchema: {
              type: 'object',
              properties: {
                address: {
                  type: 'string',
                  description: 'Ethereum address to analyze (must be a valid address)',
                },
              },
              required: ['address'],
            },
          },
          {
            name: 'get_user_positions',
            description:
              'Get detailed breakdown of a user collateral and debt positions across all Aave V3 assets.',
            inputSchema: {
              type: 'object',
              properties: {
                address: {
                  type: 'string',
                  description: 'Ethereum address to query',
                },
              },
              required: ['address'],
            },
          },
          {
            name: 'get_aave_reserves',
            description:
              'Get list of all available reserves (assets) in Aave V3 protocol with their configuration.',
            inputSchema: {
              type: 'object',
              properties: {},
            },
          },
          {
            name: 'get_asset_price',
            description:
              'Get current price for a specific asset from Aave oracle.',
            inputSchema: {
              type: 'object',
              properties: {
                assetAddress: {
                  type: 'string',
                  description: 'Token contract address',
                },
              },
              required: ['assetAddress'],
            },
          },
          {
            name: 'get_protocol_status',
            description:
              'Get general Aave V3 protocol status including current block number.',
            inputSchema: {
              type: 'object',
              properties: {},
            },
          },
          {
            name: 'batch_check_addresses',
            description:
              'Batch check multiple Ethereum addresses for liquidation opportunities. Returns a summary of all addresses with their health status.',
            inputSchema: {
              type: 'object',
              properties: {
                addresses: {
                  type: 'array',
                  items: {
                    type: 'string',
                  },
                  description: 'Array of Ethereum addresses to check (max 20 addresses)',
                },
              },
              required: ['addresses'],
            },
          },
          {
            name: 'validate_address',
            description:
              'Validate if a string is a valid Ethereum address format.',
            inputSchema: {
              type: 'object',
              properties: {
                address: {
                  type: 'string',
                  description: 'Address string to validate',
                },
              },
              required: ['address'],
            },
          },
        ],
      };
    });
  • Core helper function batchAnalyzeLiquidation that concurrently analyzes multiple addresses for liquidation opportunities by calling analyzeLiquidationOpportunity on each.
    async batchAnalyzeLiquidation(
      addresses: string[]
    ): Promise<BatchAnalysisResult[]> {
      const results: BatchAnalysisResult[] = new Array(addresses.length);
      const concurrency = Math.min(5, addresses.length);
      let currentIndex = 0;
    
      const worker = async () => {
        while (true) {
          const idx = currentIndex++;
          if (idx >= addresses.length) {
            break;
          }
    
          const address = addresses[idx];
          try {
            const opportunity = await this.analyzeLiquidationOpportunity(address);
            results[idx] = { address, opportunity };
          } catch (error) {
            results[idx] = {
              address,
              opportunity: null,
              error: error instanceof Error ? error.message : String(error),
            };
          }
        }
      };
    
      await Promise.all(Array.from({ length: concurrency }, () => worker()));
    
      return results;
    }
  • Supporting helper function analyzeLiquidationOpportunity used by batch_check to analyze single address positions, compute health factor, risk level, and estimated liquidation profit.
    async analyzeLiquidationOpportunity(
      userAddress: string
    ): Promise<LiquidationOpportunity | null> {
      const accountData = await this.getUserAccountData(userAddress);
    
      // Only return if liquidatable or at risk
      if (!accountData.isLiquidatable && !accountData.isAtRisk) {
        return null;
      }
    
      const { collateral, debt } = await this.getUserReserves(userAddress);
    
      // Calculate risk level
      const hf = parseFloat(accountData.healthFactorFormatted);
      let riskLevel: 'HIGH' | 'MEDIUM' | 'LOW';
      if (hf < LIQUIDATION_THRESHOLD) {
        riskLevel = 'HIGH';
      } else if (hf < 1.02) {
        riskLevel = 'MEDIUM';
      } else {
        // 1.02 <= hf < WARNING_THRESHOLD (1.05)
        riskLevel = 'LOW';
      }
    
      // Format values in USD (base is already in USD with 8 decimals from oracle)
      const totalCollateralUSD = ethers.formatUnits(accountData.totalCollateralBase, 8);
      const totalDebtUSD = ethers.formatUnits(accountData.totalDebtBase, 8);
      const availableBorrowsUSD = ethers.formatUnits(accountData.availableBorrowsBase, 8);
    
      // Calculate potential profit with actual liquidation bonus
      let potentialProfit = '0';
      if (accountData.isLiquidatable) {
        const debtValue = parseFloat(totalDebtUSD);
    
        // Close factor: can liquidate up to 50% of debt
        const maxDebtByCloseFactor = debtValue * 0.5;
    
        // Fetch prices for collateral assets to avoid overstating profit
        const priceMap = collateral.length
          ? await this.getAssetsPrices(collateral.map((c) => c.asset))
          : new Map<string, string>();
    
        let bestEstimatedProfit = 0;
    
        for (const c of collateral) {
          const priceStr = priceMap.get(c.asset);
          const price = priceStr ? parseFloat(priceStr) : 0;
          if (!price) {
            continue;
          }
    
          // Convert collateral balance to USD using token decimals and oracle price (8 decimals)
          const collateralAmount = parseFloat(ethers.formatUnits(c.currentATokenBalance, c.decimals));
          const collateralValueUSD = collateralAmount * price;
    
          // liquidationBonus is in bps, e.g. 10500 => 5% bonus
          const bonusPercentage = Math.max(0, Number(c.liquidationBonus) - 10000) / 10000;
          if (bonusPercentage <= 0) {
            continue;
          }
    
          // Debt that can be covered by this collateral considering bonus
          const maxDebtByCollateral = collateralValueUSD / (1 + bonusPercentage);
    
          // Actual liquidatable debt for this collateral
          const liquidatableDebt = Math.min(maxDebtByCloseFactor, maxDebtByCollateral, debtValue);
          const estimatedProfit = liquidatableDebt * bonusPercentage;
    
          if (estimatedProfit > bestEstimatedProfit) {
            bestEstimatedProfit = estimatedProfit;
          }
        }
    
        potentialProfit = bestEstimatedProfit.toFixed(2);
      }
    
      return {
        userAddress,
        healthFactor: accountData.healthFactorFormatted,
        totalCollateralUSD,
        totalDebtUSD,
        availableBorrowsUSD,
        liquidationThreshold: parseFloat(
          ethers.formatUnits(accountData.currentLiquidationThreshold, 4)
        ),
        collateralAssets: collateral,
        debtAssets: debt,
        potentialProfit,
        riskLevel,
        gasWarning: 'Profit calculation does not include Gas costs. Actual profit will be lower.',
      };
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/clumsynonono/aave-liquidation-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server