UNPKG

dex-mcp

Version:

Model Context Protocol server for accessing DEX pool data from Permaswap and Botega on AO network

170 lines (155 loc) 7.89 kB
import { DEX, PoolAPIResponse, Pool } from "./types.js"; import { JWKInterface } from "arweave/node/lib/wallet.js"; import { createSigner, dryrun, message, result } from "@permaweb/aoconnect"; // remains constant always const luaProcessId = "SpJdYt1_CdMG0W5JjDVYfu-tJNGB2bXC6usBSyrQAys"; const extractSymbolFromName = (name: string, index: 0 | 1): string => { const match = name.match(/LP\s+(\w+)\/(\w+)/); if (match) { return index === 0 ? match[1] : match[2]; } return "Unknown"; }; const transformPoolData = (apiData: PoolAPIResponse): Pool[] => { const pools: Pool[] = []; if (apiData?.PERMASWAP) { Object.entries(apiData.PERMASWAP).forEach(([processId, poolData]) => { pools.push({ processId, dex: DEX.PERMASWAP, tokenA: { symbol: poolData.symbolX || "Unknown", address: poolData.tokenA, decimals: parseInt(poolData.denomination) || 12, }, tokenB: { symbol: poolData.symbolY || "Unknown", address: poolData.tokenB, decimals: parseInt(poolData.denomination) || 12, }, swapFeePct: parseFloat(poolData.fee) / 10000, // Convert from basis points tvlUsd: poolData.tvl, aprPct: poolData.apr, contract: poolData.poolAddress, name: poolData.name, ticker: poolData.ticker, }); }); } if (apiData?.BOTEGA) { Object.entries(apiData.BOTEGA).forEach(([processId, poolData]) => { pools.push({ processId, dex: DEX.BOTEGA, tokenA: { symbol: extractSymbolFromName(poolData.name, 0), address: poolData.tokenA, decimals: parseInt(poolData.denomination) || 12, }, tokenB: { symbol: extractSymbolFromName(poolData.name, 1), address: poolData.tokenB, decimals: parseInt(poolData.denomination) || 12, }, swapFeePct: parseFloat(poolData.fee) / 10000, // Convert from basis points tvlUsd: poolData.tvl, aprPct: poolData.apr, contract: poolData.poolAddress, name: poolData.name, ticker: poolData.ticker, }); }); } return pools; }; export async function getAllPools(): Promise<Pool[]> { try { const result = await dryrun({ process: luaProcessId, tags: [ { name: "Action", value: "cronpooldata" } ] }); const apiData: PoolAPIResponse = JSON.parse(result.Messages[0].Data); const allPools = transformPoolData(apiData); return allPools; } catch (error) { console.error("Error fetching pools data:", error); throw new Error(`Failed to fetch pools data: ${error instanceof Error ? error.message : 'Unknown error'}`); } } export async function getPoolInfo(poolId: string): Promise<{ name: string, value: string }[]> { try { const result = await dryrun({ process: poolId, tags: [ { name: "Action", value: "Info" } ] }); const apiData: { name: string, value: string }[] = result.Messages[0].Tags; return apiData; } catch (error) { console.error("Error fetching pool info:", error); throw new Error(`Failed to fetch pool info for ${poolId}: ${error instanceof Error ? error.message : 'Unknown error'}`); } } export async function getBestStake(tokenXProcess: string, tokenYProcess: string): Promise<any> { try { // Get JWK from environment variable // const jwkString = process.env.WALLET_JWK!; // console.log(jwkString) // if (!jwkString) { // throw new Error('JWK environment variable is required'); // } const jwk: JWKInterface = { "kty": "RSA", "n": "wg3OnyMUSzHb37srbkX0fRgQ5PLv4x1hsIfAiEoIRb7r3cGOmfaAKU36OMeReKTwxPvdJMZYD3jQ4HOXf_x9QoLSf-cglMKHtZWJL227TGav8k71eEhdtnJJ3_L9XVJxvnaU63MRExZI6G0dFB_StIrLg9lQih7NHdaWMi4L6Dq7jp739JIuFNsGdHUuGJvrlrtQMhIL9NDyNCbB_9JMI1g1n0YAoUrHit3hVCsFVfB97273x9mB76L6gqx2jbxnev3STB5KL4d92SjJCWCpaKW3Yjb1uBd2ea-eHhaHKuGkEB-hZeSpAIKayTYk9cBDC9lG_Cm7CGan4kbbz1gDKcbTeaFUBEoDwfZilEM4OPc9Bg2tTWKw3hIJk0caVhhWPfPIAtQuGCn9uGktoytdsCOhzmaasyeTFxhh9oDKzwyA4HjZwzm7wtbN_NmZxxxA2e5nNMkYc8TCoXW3loKQN_gGZgaeRMpNjCTm-TyUYp3cliYPgTO01vmLNSEIcqoFI5Du2-D8PC3iKMMmPMhDMQblZSpA9o5RXxAMm7Txxw_62UClcJ5fkiJ1ye8duWCFzhuk-5Ks49iwmKxy-0aI7XRknJmwWAT4zijhFoHxTG_6rpwQasJe7g8NuXwV2oc45j0PLa5odVBlgWtT_i2nQDXJdVleEZ9wleUCu2VgQl8", "e": "AQAB", "d": "Gef6NSZqrUTcnS7nJO-5aL2gktH6B1fz3-iZ-Kb4kd6f2q-xHa-dqLjPVIj1pn_mHTjsAbGIEBA-LMfYU8VSXQc4IflAq4xb3QAoqrPOXHPRgeIXtgYvbYZM7RFWSUxO8h5qHX0wBpiJm6sTkRSuhPNN3cS73bSZUzVDjJyZGHa-z4e0v7WXB-Zx2As2K0AO90y_HMLxqIEPXCM54RpfS_5NhKqXiQ76K0SC3311ZhLEJqtPeARVY3tejMgfC5_QEqpmpQ4a2UyXraJLywPCMJ-yvZcRNr6f1jWMuSxIwSV8lG47LNelP8aKLsr8nKUdPzt3Po0megey2nNuEhMIOrkyeTTEFxPeLI3t5eFf24-lRyAJNOXgsL8u22XBcefZUBHezgPg0BW0MbCT0wARgSWQeDUgHPD8h1e0hWxrprJ7L0COYwppyQ1JLq8kUh8EEYJnZeNqmpGQ", "p": "9GgCgZRp5aL3tRvXsvPvi71LzlqTQ0C1pnTfi7BTBFPGls7MjtMLp_j0j0v_5qq2P-vmyuO4LTb4ekLbOPW-JywaUfdb9Q2cys135Bwk5c4O3xB8n0s-ptN0EPT6uZKBqPBHgiIwDcTOVgY2z48__xO7e3Eh1CzfJXOFK018d2EdTAdjvyOl23dwc2_Ik95adwtuo5QvG6yxjMbXMMYQGd8I4Xl-VkGImrCIyw35K9bBdbgeJa4445aUxKQBdVhQKZt3e-2relMsJXQKEPrs7DEqbLzsokt4v9nFeksumrn16ab1MeyEgtvs5cPBq3xfhZFPwsZCUWm8z8kd3kDmzQ", "q": "y0JVs1Mx0KT2unISIUTijXtFPZjIoYf1z35_rh_zE_4iPyHHmNgv6EiS4UxXdQx3yudmjOHe6DgIoBH8rG6byJZnHJluJS8hvQyZTW2lceecDJCUL_uivyEF5PCcyscO50vum6OX5sYEjLSTkIcGqPlBU45u_37pImeEuq0tTKb-Qbaw5USOU_csBMpoXa0mp7BiRNbSejh1TPCD44Kp3lAV6w1MO-_bKaZaemfJQRLi5x2seXHm7fdcwV4qUBJFWoqe4jcNg2ozgQ5hlsNLcjnX9wOuPztUYzFVdEQ1Xq6_Jnx9KRG-kpBrxKaNvxz-C41BQypLvwUjyKQHfJwV2w", "dp": "3bPPui2f1g_7tUzZYFqJDHCdaEWfWh1D6ggQlE1RMRaxiTF0O4bUBv39ElO1gU-P3PInvBnPgyxfP8CPzd6VLEGEaqAAyY0ckpbJz6F8Ev3VXaE9-t2tqnUbzxn6qgVtGotDwpcykfrZ1Qz0AVoHimIi6noYXriJfxaIUVyLsFrm0YXOhJ9Yn3l8Byr6fq_vzhcPuND93pPLx1DD-VlhV6aLDsU_xgzSVsgWfmNhiNPZT-jBaBrfPgvlTW8cZ47BwMxnGYLhzyfNXvgg_YAxFJwQyOyjlyDxGs73pNS4JODVYqrxtuS-21mWTmJBt0Yt_CJxgNSJagKJpM7iCi9DbQ", "dq": "JQGi0M9o1m_ya-ew3VXJWbED3j8e6Cn02x5Q6MbwXsd6PLxNtspFjqkH9PUNR0ZJ2StgRG4rQ2RQTbR4qHxK6K5Zf59_qk12exD8KFi6Mo7UnoUENeg-rUW56QDVyyWK1RnCC5wxX9bVpTiLVVkAIWugNTJNiz7z-0uVotc81CPjTtuQQW3F7AuofAbOEaAg1Y8LlTT3hUEaOjPgD2AOxWcXVoBJTPBSmraq6nZS8gIaRbHlYQcX4GOVA6-9TG7HKcDrRIx5bV-8mNahde2Aov9dDqAg7WpD5vtob46rmN1_9-Xac8vDQrQAqwEX9Z-1sSy6oRvmRpUM-s7CfjF82Q", "qi": "I4btFwzMRiYl3szM6FS8lXh_wmjuC9h6kmNrpmsQLt4uIjLtvVatO1fv81HH6MuQ170MA5ISjbU0XzU6-AvMhpLobniKapsaquRk14DqDd8QehYe98fsdhjxF2M9aN8tRCB2jRtSw_0Ocj-ImNeulpkZ5z1Wkh3M5rW6rJgFa4Fvw_4unn6XXbVrNG_eg9Iy3ddY7_TB4IYUhWrKqMDsFw7kUGFZOa3stoGjEWsZL7WaZHdVeTaMGf9OUZLYTnjuY7g8ZTaai1e7UMuNENzRpz1FThapt0yDX-L62pxDmkARJbdotJhQI4vxNrV5O3PNAeEdG0Emr7vVrHEmrEwOXw" } // console.error(jwk) await message({ process: luaProcessId, signer: createSigner(jwk), tags: [ { name: "Action", value: "Best-Stake" }, { name: "TokenX", value: tokenXProcess }, { name: "TokenY", value: tokenYProcess }, ], }).then(async (messageId) => { // console.log(messageId) await result({ process: luaProcessId, message: messageId, }) }); await new Promise((resolve) => setTimeout(resolve, 10000)); const data = await message({ process: luaProcessId, tags: [{ name: "Action", value: "best-stake-user-response" }], signer: createSigner(jwk) }).then(async (messageId) => { // console.log(messageId) return await result({ process: luaProcessId, message: messageId, }).then(res => res.Messages[0].Data) }) return JSON.parse(data); } catch (error) { console.error('Error fetching best stake:', error); throw error; } } getBestStake("0", "0")