getWalletPnl
Calculate profit and loss for an Ethereum wallet by analyzing transaction history. Input the wallet address and chain to track financial performance and portfolio changes.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | ||
| chain | No | eth |
Implementation Reference
- tools/profitability.js:19-79 (handler)The async handler function that executes the getWalletPnl tool logic. It uses the Moralis API via PowerShell to fetch wallet profitability data, processes the response to compute summary statistics like total invested, realized profit/loss, and counts of profitable/unprofitable tokens, then returns a formatted text response.async ({ address, chain }) => { try { // Use API key from environment variable const apiKey = process.env.MORALIS_API_KEY; if (!apiKey) { throw new Error("MORALIS_API_KEY environment variable is not set"); } // Format the URL for PowerShell request const url = `https://deep-index.moralis.io/api/v2.2/wallets/${address}/profitability?chain=${chain}`; const psCommand = `powershell -Command "Invoke-RestMethod -Method Get -Uri '${url}' -Headers @{'X-API-Key'='${apiKey}'; 'accept'='application/json'} | ConvertTo-Json -Depth 10"`; // Execute PowerShell command const { stdout } = await execPromise(psCommand); const response = JSON.parse(stdout); // Get profit/loss data from the response const tokens = response.result || []; // Process data - calculate some summary statistics let totalRealizedProfit = 0; let totalInvested = 0; let profitableTokens = 0; let unprofitableTokens = 0; tokens.forEach(token => { if (token.realized_profit_usd) { totalRealizedProfit += parseFloat(token.realized_profit_usd); } if (token.total_usd_invested) { totalInvested += parseFloat(token.total_usd_invested); } if (parseFloat(token.realized_profit_percentage || 0) > 0) { profitableTokens++; } else if (parseFloat(token.realized_profit_percentage || 0) < 0) { unprofitableTokens++; } }); return { content: [{ type: "text", text: `Wallet PnL for ${address} on chain ${chain}:\n` + `Summary: ${tokens.length} tokens analyzed\n` + `Total invested: $${totalInvested.toFixed(2)}\n` + `Total realized profit/loss: $${totalRealizedProfit.toFixed(2)}\n` + `Profitable tokens: ${profitableTokens}, Unprofitable tokens: ${unprofitableTokens}\n\n` + `Detailed results: ${JSON.stringify(tokens, null, 2)}` }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching wallet profitability: ${error.message}` }] }; } } );
- tools/profitability.js:15-18 (schema)Zod input schema validation for the tool: 'address' must be a valid Ethereum address (0x followed by 40 hex chars), 'chain' is optional string defaulting to 'eth'.{ address: z.string().regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address"), chain: z.string().optional().default("eth") },
- tools/profitability.js:12-80 (registration)The registration of the 'getWalletPnl' tool via server.tool() within the exported registerProfitabilityTools function, including schema and handler.export function registerProfitabilityTools(server) { // Add wallet profitability tool server.tool("getWalletPnl", { address: z.string().regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address"), chain: z.string().optional().default("eth") }, async ({ address, chain }) => { try { // Use API key from environment variable const apiKey = process.env.MORALIS_API_KEY; if (!apiKey) { throw new Error("MORALIS_API_KEY environment variable is not set"); } // Format the URL for PowerShell request const url = `https://deep-index.moralis.io/api/v2.2/wallets/${address}/profitability?chain=${chain}`; const psCommand = `powershell -Command "Invoke-RestMethod -Method Get -Uri '${url}' -Headers @{'X-API-Key'='${apiKey}'; 'accept'='application/json'} | ConvertTo-Json -Depth 10"`; // Execute PowerShell command const { stdout } = await execPromise(psCommand); const response = JSON.parse(stdout); // Get profit/loss data from the response const tokens = response.result || []; // Process data - calculate some summary statistics let totalRealizedProfit = 0; let totalInvested = 0; let profitableTokens = 0; let unprofitableTokens = 0; tokens.forEach(token => { if (token.realized_profit_usd) { totalRealizedProfit += parseFloat(token.realized_profit_usd); } if (token.total_usd_invested) { totalInvested += parseFloat(token.total_usd_invested); } if (parseFloat(token.realized_profit_percentage || 0) > 0) { profitableTokens++; } else if (parseFloat(token.realized_profit_percentage || 0) < 0) { unprofitableTokens++; } }); return { content: [{ type: "text", text: `Wallet PnL for ${address} on chain ${chain}:\n` + `Summary: ${tokens.length} tokens analyzed\n` + `Total invested: $${totalInvested.toFixed(2)}\n` + `Total realized profit/loss: $${totalRealizedProfit.toFixed(2)}\n` + `Profitable tokens: ${profitableTokens}, Unprofitable tokens: ${unprofitableTokens}\n\n` + `Detailed results: ${JSON.stringify(tokens, null, 2)}` }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching wallet profitability: ${error.message}` }] }; } } ); }