@iqai/mcp-bamm
Version:
MCP server for bamm (borrow automated market maker)
91 lines (90 loc) • 3.63 kB
JavaScript
import dedent from "dedent";
import { BAMM_ADDRESSES } from "../constants.js";
import { BAMM_FACTORY_ABI } from "../lib/bamm-factory.abi.js";
import { BAMM_ABI } from "../lib/bamm.abi.js";
import formatNumber from "../lib/format-number.js";
export class BammPoolsStatsService {
walletService;
// Frax API endpoint for all Fraxswap pools
endpoint = "https://api.frax.finance/v2/fraxswap/pools";
constructor(walletService) {
this.walletService = walletService;
}
async getPoolsStats() {
const publicClient = this.walletService.getPublicClient();
const zeroAddress = "0x0000000000000000000000000000000000000000";
// 1. Get the list of all BAMM addresses from the factory.
const bammsOnChain = await publicClient.readContract({
address: BAMM_ADDRESSES.FACTORY,
abi: BAMM_FACTORY_ABI,
functionName: "bammsArray",
args: [],
});
// 2. Build a mapping: underlying Fraxswap pair address -> BAMM address.
const pairToBammMap = new Map();
for (const bammAddress of bammsOnChain) {
if (bammAddress === zeroAddress)
continue;
// Get the Fraxswap pair address from this BAMM contract.
const pairAddress = await publicClient.readContract({
address: bammAddress,
abi: BAMM_ABI,
functionName: "pair",
args: [],
});
if (pairAddress && pairAddress !== zeroAddress) {
pairToBammMap.set(pairAddress.toLowerCase(), bammAddress);
}
}
// 3. Fetch the full list of pools from the Frax API endpoint.
const response = await fetch(this.endpoint);
if (!response.ok) {
throw new Error(`Failed to fetch pools: ${response.statusText}`);
}
const data = await response.json();
// Map the API response to our PoolStats type and add placeholder fields.
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
const allPools = data.pools.map((pool) => ({
...pool,
bammAddress: "",
bammApr: 0,
fraxswapApr: 0,
}));
// 4. Filter the API pools to only include those with a matching pair address.
const filteredPools = [];
for (const pool of allPools) {
const poolPair = pool.poolAddress.toLowerCase();
if (pairToBammMap.has(poolPair)) {
// Set the BAMM address from our mapping.
pool.bammAddress = pairToBammMap.get(poolPair) ?? "";
filteredPools.push(pool);
}
}
filteredPools.sort((a, b) => b.tvl - a.tvl);
return filteredPools;
}
formatPoolsStats(pools) {
if (pools.length === 0) {
return "📊 No BAMM Pools Found";
}
const formattedStats = pools
.map((pool) => {
const poolName = `${pool.token0Symbol}/${pool.token1Symbol}`;
return dedent `
📊 Pool: ${poolName}
- Pool Address: ${pool.poolAddress}
- BAMM Address: ${pool.bammAddress}
- TVL: $${formatNumber(pool.tvl || 0)}
- ${pool.token0Symbol} Locked: ${formatNumber(pool.token0AmountLocked || 0)}
- ${pool.token1Symbol} Locked: ${formatNumber(pool.token1AmountLocked || 0)}
`;
})
.join("\n\n");
return dedent `
📊 *BAMM Pool Stats:*
Total: ${pools.length}
${formattedStats}
`;
}
}
//# sourceMappingURL=pool-stats.js.map