Skip to main content
Glama
lordbasilaiassistant-sudo

base-flash-arb-mcp

estimate_flash_profit

Calculate potential profit from arbitrage opportunities using flash loans on Base network. Estimates net earnings after accounting for gas fees when exploiting price differences between two liquidity pools.

Instructions

Given two pools with a price difference, estimate flash loan profit after gas.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
token_addressYesToken contract address
pool_a_addressYesAddress of pool A (buy cheap here)
pool_b_addressYesAddress of pool B (sell expensive here)
loan_amount_ethNoFlash loan amount in ETH (default 1.0)1.0

Implementation Reference

  • The tool "estimate_flash_profit" is defined and implemented here. It calculates the price difference between two liquidity pools and estimates potential profit from a flash loan, accounting for flash loan fees and gas costs.
    server.tool(
      "estimate_flash_profit",
      "Given two pools with a price difference, estimate flash loan profit after gas.",
      {
        token_address: z.string().describe("Token contract address"),
        pool_a_address: z.string().describe("Address of pool A (buy cheap here)"),
        pool_b_address: z.string().describe("Address of pool B (sell expensive here)"),
        loan_amount_eth: z
          .string()
          .default("1.0")
          .describe("Flash loan amount in ETH (default 1.0)"),
      },
      async ({ token_address, pool_a_address, pool_b_address, loan_amount_eth }) => {
        try {
          const symbol = await getSymbol(token_address);
          const loanWei = ethers.parseEther(loan_amount_eth);
          const gasCost = await estimateGasCost();
    
          // Identify pool types by checking factories
          const v2Factory = new ethers.Contract(
            UNIV2_FACTORY,
            UNIV2_FACTORY_ABI,
            provider
          );
          const aeroFactory = new ethers.Contract(
            AERO_FACTORY,
            AERO_FACTORY_ABI,
            provider
          );
    
          // Try to get reserves from both pools
          const pairAbi = [
            ...UNIV2_PAIR_ABI,
            "function stable() view returns (bool)",
          ];
    
          async function getPoolPrice(
            poolAddr: string
          ): Promise<{ priceInWeth: number; type: string } | null> {
            try {
              const pair = new ethers.Contract(poolAddr, pairAbi, provider);
              const [r0, r1] = await pair.getReserves();
              const t0: string = await pair.token0();
              const isWeth0 = t0.toLowerCase() === WETH.toLowerCase();
              const wethRes = isWeth0 ? r0 : r1;
              const tokenRes = isWeth0 ? r1 : r0;
    
              if (tokenRes === 0n) return null;
    
              const price =
                Number(ethers.formatEther(wethRes)) /
                Number(ethers.formatUnits(tokenRes, 18));
    
              // Detect type
              let poolType = "unknown";
              try {
                const v2Pair = await v2Factory.getPair(WETH, token_address);
                if (v2Pair.toLowerCase() === poolAddr.toLowerCase())
                  poolType = "Uniswap V2";
              } catch { /* ignore */ }
              try {
                for (const stable of [false, true]) {
                  const aeroPool = await aeroFactory.getPool(
                    WETH,
                    token_address,
                    stable
                  );
                  if (aeroPool.toLowerCase() === poolAddr.toLowerCase())
                    poolType = `Aerodrome (${stable ? "stable" : "volatile"})`;
                }
              } catch { /* ignore */ }
    
              return { priceInWeth: price, type: poolType };
            } catch {
              return null;
            }
          }
    
          const [poolAInfo, poolBInfo] = await Promise.all([
            getPoolPrice(pool_a_address),
            getPoolPrice(pool_b_address),
          ]);
    
          if (!poolAInfo || !poolBInfo) {
            return {
              content: [
                {
                  type: "text" as const,
                  text: JSON.stringify({
                    error: "Could not read reserves from one or both pools",
                    poolA: poolAInfo ? "OK" : "FAILED",
                    poolB: poolBInfo ? "OK" : "FAILED",
                  }),
                },
              ],
              isError: true,
            };
          }
    
          // Calculate arb: buy cheap on A, sell expensive on B
          const priceDiffBps = Math.abs(
            ((poolAInfo.priceInWeth - poolBInfo.priceInWeth) /
              Math.min(poolAInfo.priceInWeth, poolBInfo.priceInWeth)) *
              10000
          );
    
          // Estimate tokens from loan
          const cheaperPool =
            poolAInfo.priceInWeth < poolBInfo.priceInWeth ? "A" : "B";
          const cheapPrice = Math.min(poolAInfo.priceInWeth, poolBInfo.priceInWeth);
          const expPrice = Math.max(poolAInfo.priceInWeth, poolBInfo.priceInWeth);
    
          const tokensFromLoan =
            cheapPrice > 0
              ? Number(ethers.formatEther(loanWei)) / cheapPrice
              : 0;
          const ethFromSell = tokensFromLoan * expPrice;
          const grossProfitEth =
            ethFromSell - Number(ethers.formatEther(loanWei));
          const flashLoanFee = Number(ethers.formatEther(loanWei)) * 0.0009; // Aave 0.09%
          const netProfitEth =
            grossProfitEth -
            flashLoanFee -
            Number(ethers.formatEther(gasCost));
    
          return {
            content: [
              {
                type: "text" as const,
                text: JSON.stringify(
                  {
                    token: token_address,
                    symbol,
                    loanAmountEth: loan_amount_eth,
                    poolA: {
                      address: pool_a_address,
                      type: poolAInfo.type,
                      priceInWeth: poolAInfo.priceInWeth.toFixed(18),
                    },
                    poolB: {
                      address: pool_b_address,
                      type: poolBInfo.type,
                      priceInWeth: poolBInfo.priceInWeth.toFixed(18),
                    },
                    priceDiffBps: Math.round(priceDiffBps),
                    buyOn: cheaperPool === "A" ? "Pool A" : "Pool B",
                    sellOn: cheaperPool === "A" ? "Pool B" : "Pool A",
                    estimatedTokens: tokensFromLoan.toFixed(4),
                    ethFromSell: ethFromSell.toFixed(6),
                    grossProfitEth: grossProfitEth.toFixed(6),
                    flashLoanFeeEth: flashLoanFee.toFixed(6),
                    gasCostEth: ethers.formatEther(gasCost),
                    netProfitEth: netProfitEth.toFixed(6),
                    profitable: netProfitEth > 0,
                    warning:
                      "Estimates assume no slippage. Real execution will have slippage proportional to trade size vs pool liquidity.",
                  },
                  null,
                  2

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/lordbasilaiassistant-sudo/base-flash-arb-mcp'

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